marco.pms.mobileapp/lib/view/employees/employee_detail_screen.dart

293 lines
9.8 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:marco/controller/employee/employees_screen_controller.dart';
import 'package:marco/helpers/widgets/custom_app_bar.dart';
import 'package:marco/helpers/widgets/avatar.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/utils/launcher_utils.dart';
import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
class EmployeeDetailPage extends StatefulWidget {
final String employeeId;
final bool fromProfile;
const EmployeeDetailPage({
super.key,
required this.employeeId,
this.fromProfile = false,
});
@override
State<EmployeeDetailPage> createState() => _EmployeeDetailPageState();
}
class _EmployeeDetailPageState extends State<EmployeeDetailPage> {
final EmployeesScreenController controller =
Get.put(EmployeesScreenController());
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
controller.fetchEmployeeDetails(widget.employeeId);
});
}
@override
void dispose() {
controller.selectedEmployeeDetails.value = null;
super.dispose();
}
String _getDisplayValue(dynamic value) {
if (value == null || value.toString().trim().isEmpty || value == 'null') {
return 'NA';
}
return value.toString();
}
String _formatDate(DateTime? date) {
if (date == null || date == DateTime(1)) return 'NA';
try {
return DateFormat('d/M/yyyy').format(date);
} catch (_) {
return 'NA';
}
}
Widget _buildLabelValueRow(String label, String value,
{bool isMultiLine = false}) {
final lowerLabel = label.toLowerCase();
final isEmail = lowerLabel == 'email';
final isPhone =
lowerLabel == 'phone number' || lowerLabel == 'emergency phone number';
void handleTap() {
if (value == 'NA') return;
if (isEmail) {
LauncherUtils.launchEmail(value);
} else if (isPhone) {
LauncherUtils.launchPhone(value);
}
}
void handleLongPress() {
if (value == 'NA') return;
LauncherUtils.copyToClipboard(value, typeLabel: label);
}
final valueWidget = GestureDetector(
onTap: (isEmail || isPhone) ? handleTap : null,
onLongPress: (isEmail || isPhone) ? handleLongPress : null,
child: Text(
value,
style: TextStyle(
fontWeight: FontWeight.normal,
color: (isEmail || isPhone) ? Colors.indigo : Colors.black54,
fontSize: 14,
decoration: (isEmail || isPhone)
? TextDecoration.underline
: TextDecoration.none,
),
),
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isMultiLine) ...[
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 14,
),
),
MySpacing.height(4),
valueWidget,
] else
GestureDetector(
onTap: (isEmail || isPhone) ? handleTap : null,
onLongPress: (isEmail || isPhone) ? handleLongPress : null,
child: RichText(
text: TextSpan(
text: "$label: ",
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 14,
),
children: [
TextSpan(
text: value,
style: TextStyle(
fontWeight: FontWeight.normal,
color:
(isEmail || isPhone) ? Colors.indigo : Colors.black54,
decoration: (isEmail || isPhone)
? TextDecoration.underline
: TextDecoration.none,
),
),
],
),
),
),
MySpacing.height(10),
Divider(color: Colors.grey[300], height: 1),
MySpacing.height(10),
],
);
}
Widget _buildInfoCard(employee) {
return Card(
elevation: 3,
shadowColor: Colors.black12,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 16, 12, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MySpacing.height(12),
_buildLabelValueRow('Email', _getDisplayValue(employee.email)),
_buildLabelValueRow(
'Phone Number', _getDisplayValue(employee.phoneNumber)),
_buildLabelValueRow('Emergency Contact Person',
_getDisplayValue(employee.emergencyContactPerson)),
_buildLabelValueRow('Emergency Phone Number',
_getDisplayValue(employee.emergencyPhoneNumber)),
_buildLabelValueRow('Gender', _getDisplayValue(employee.gender)),
_buildLabelValueRow('Birth Date', _formatDate(employee.birthDate)),
_buildLabelValueRow(
'Joining Date', _formatDate(employee.joiningDate)),
_buildLabelValueRow(
'Current Address',
_getDisplayValue(employee.currentAddress),
isMultiLine: true,
),
_buildLabelValueRow(
'Permanent Address',
_getDisplayValue(employee.permanentAddress),
isMultiLine: true,
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
final bool showAppBar = !widget.fromProfile;
return Scaffold(
backgroundColor: const Color(0xFFF1F1F1),
appBar: showAppBar
? CustomAppBar(
title: 'Employee Details',
onBackPressed: () {
if (widget.fromProfile) {
Get.back();
} else {
Get.offNamed('/dashboard/employees');
}
},
)
: null,
body: Obx(() {
if (controller.isLoadingEmployeeDetails.value) {
return const Center(child: CircularProgressIndicator());
}
final employee = controller.selectedEmployeeDetails.value;
if (employee == null) {
return const Center(child: Text('No employee details found.'));
}
return SafeArea(
child: MyRefreshIndicator(
onRefresh: () async {
await controller.fetchEmployeeDetails(widget.employeeId);
},
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.fromLTRB(12, 20, 12, 80),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
children: [
Avatar(
firstName: employee.firstName,
lastName: employee.lastName,
size: 45,
),
MySpacing.width(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.titleMedium(
'${employee.firstName} ${employee.lastName}',
fontWeight: 700,
),
MySpacing.height(6),
MyText.bodySmall(
_getDisplayValue(employee.jobRole),
fontWeight: 500,
),
],
),
),
IconButton(
icon:
const Icon(Icons.edit, size: 24, color: Colors.red),
onPressed: () async {
final result =
await showModalBottomSheet<Map<String, dynamic>>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => AddEmployeeBottomSheet(
employeeData: {
'id': employee.id,
'first_name': employee.firstName,
'last_name': employee.lastName,
'phone_number': employee.phoneNumber,
'email': employee.email,
'hasApplicationAccess':
employee.hasApplicationAccess,
'gender': employee.gender.toLowerCase(),
'job_role_id': employee.jobRoleId,
'joining_date':
employee.joiningDate?.toIso8601String(),
},
),
);
if (result != null) {
controller.fetchEmployeeDetails(widget.employeeId);
}
},
),
],
),
MySpacing.height(14),
_buildInfoCard(employee),
],
),
),
),
);
}),
);
}
}