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/view/employees/assign_employee_bottom_sheet.dart'; import 'package:marco/helpers/utils/launcher_utils.dart'; import 'package:marco/controller/permission_controller.dart'; import 'package:marco/helpers/utils/permission_constants.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 createState() => _EmployeeDetailPageState(); } class _EmployeeDetailPageState extends State { final EmployeesScreenController controller = Get.put(EmployeesScreenController()); final PermissionController _permissionController = Get.find(); @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>( 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, '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), ], ), ), ), ); }), floatingActionButton: Obx(() { if (!_permissionController.hasPermission(Permissions.assignToProject)) { return const SizedBox.shrink(); } if (controller.isLoadingEmployeeDetails.value || controller.selectedEmployeeDetails.value == null) { return const SizedBox.shrink(); } final employee = controller.selectedEmployeeDetails.value!; return FloatingActionButton.extended( onPressed: () { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => AssignProjectBottomSheet( employeeId: widget.employeeId, jobRoleId: employee.jobRoleId, ), ); }, backgroundColor: Colors.red, icon: const Icon(Icons.assignment), label: const Text( 'Assign to Project', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500), ), ); }), ); } }