import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:marco/controller/dashboard/add_employee_controller.dart'; import 'package:marco/controller/dashboard/employees_screen_controller.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/widgets/my_text_style.dart'; import 'package:marco/helpers/utils/base_bottom_sheet.dart'; class AddEmployeeBottomSheet extends StatefulWidget { @override State createState() => _AddEmployeeBottomSheetState(); } class _AddEmployeeBottomSheetState extends State with UIMixin { final AddEmployeeController _controller = Get.put(AddEmployeeController()); @override Widget build(BuildContext context) { return GetBuilder( init: _controller, builder: (_) { return BaseBottomSheet( title: "Add Employee", onCancel: () => Navigator.pop(context), onSubmit: _handleSubmit, child: Form( key: _controller.basicValidator.formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _sectionLabel("Personal Info"), MySpacing.height(16), _inputWithIcon( label: "First Name", hint: "e.g., John", icon: Icons.person, controller: _controller.basicValidator.getController('first_name')!, validator: _controller.basicValidator.getValidation('first_name'), ), MySpacing.height(16), _inputWithIcon( label: "Last Name", hint: "e.g., Doe", icon: Icons.person_outline, controller: _controller.basicValidator.getController('last_name')!, validator: _controller.basicValidator.getValidation('last_name'), ), MySpacing.height(16), _sectionLabel("Contact Details"), MySpacing.height(16), _buildPhoneInput(context), MySpacing.height(24), _sectionLabel("Other Details"), MySpacing.height(16), _buildDropdownField( label: "Gender", value: _controller.selectedGender?.name.capitalizeFirst ?? '', hint: "Select Gender", onTap: () => _showGenderPopup(context), ), MySpacing.height(16), _buildDropdownField( label: "Role", value: _controller.roles.firstWhereOrNull((role) => role['id'] == _controller.selectedRoleId)?['name'] ?? "", hint: "Select Role", onTap: () => _showRolePopup(context), ), ], ), ), ); }, ); } // Submit logic Future _handleSubmit() async { final result = await _controller.createEmployees(); if (result != null && result['success'] == true) { final employeeData = result['data']; // ✅ Safe now final employeeController = Get.find(); final projectId = employeeController.selectedProjectId; if (projectId == null) { await employeeController.fetchAllEmployees(); } else { await employeeController.fetchEmployeesByProject(projectId); } employeeController.update(['employee_screen_controller']); _controller.basicValidator.getController("first_name")?.clear(); _controller.basicValidator.getController("last_name")?.clear(); _controller.basicValidator.getController("phone_number")?.clear(); _controller.selectedGender = null; _controller.selectedRoleId = null; _controller.update(); Navigator.pop(context, employeeData); } } // Section label widget Widget _sectionLabel(String title) => Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.labelLarge(title, fontWeight: 600), MySpacing.height(4), Divider(thickness: 1, color: Colors.grey.shade200), ], ); // Input field with icon Widget _inputWithIcon({ required String label, required String hint, required IconData icon, required TextEditingController controller, required String? Function(String?)? validator, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.labelMedium(label), MySpacing.height(8), TextFormField( controller: controller, validator: validator, decoration: _inputDecoration(hint).copyWith( prefixIcon: Icon(icon, size: 20), ), ), ], ); } // Phone input with country code selector Widget _buildPhoneInput(BuildContext context) { return Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(12), color: Colors.grey.shade100, ), child: PopupMenuButton>( onSelected: (country) { _controller.selectedCountryCode = country['code']!; _controller.update(); }, itemBuilder: (context) => [ PopupMenuItem( enabled: false, padding: EdgeInsets.zero, child: SizedBox( height: 200, width: 100, child: ListView( children: _controller.countries.map((country) { return ListTile( dense: true, title: Text("${country['name']} (${country['code']})"), onTap: () => Navigator.pop(context, country), ); }).toList(), ), ), ), ], child: Row( children: [ Text(_controller.selectedCountryCode), const Icon(Icons.arrow_drop_down), ], ), ), ), MySpacing.width(12), Expanded( child: TextFormField( controller: _controller.basicValidator.getController('phone_number'), validator: (value) { if (value == null || value.trim().isEmpty) { return "Phone number is required"; } final digitsOnly = value.trim(); final minLength = _controller .minDigitsPerCountry[_controller.selectedCountryCode] ?? 7; final maxLength = _controller .maxDigitsPerCountry[_controller.selectedCountryCode] ?? 15; if (!RegExp(r'^[0-9]+$').hasMatch(digitsOnly)) { return "Only digits allowed"; } if (digitsOnly.length < minLength || digitsOnly.length > maxLength) { return "Between $minLength–$maxLength digits"; } return null; }, keyboardType: TextInputType.phone, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(15), ], decoration: _inputDecoration("e.g., 9876543210").copyWith( suffixIcon: IconButton( icon: const Icon(Icons.contacts), onPressed: () => _controller.pickContact(context), ), ), ), ), ], ); } // Gender/Role field (read-only dropdown) Widget _buildDropdownField({ required String label, required String value, required String hint, required VoidCallback onTap, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.labelMedium(label), MySpacing.height(8), GestureDetector( onTap: onTap, child: AbsorbPointer( child: TextFormField( readOnly: true, controller: TextEditingController(text: value), decoration: _inputDecoration(hint).copyWith( suffixIcon: const Icon(Icons.expand_more), ), ), ), ), ], ); } // Common input decoration InputDecoration _inputDecoration(String hint) { return InputDecoration( hintText: hint, hintStyle: MyTextStyle.bodySmall(xMuted: true), filled: true, fillColor: Colors.grey.shade100, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: const BorderSide(color: Colors.blueAccent, width: 1.5), ), contentPadding: MySpacing.all(16), ); } // Gender popup menu void _showGenderPopup(BuildContext context) async { final selected = await showMenu( context: context, position: _popupMenuPosition(context), items: Gender.values.map((gender) { return PopupMenuItem( value: gender, child: Text(gender.name.capitalizeFirst!), ); }).toList(), ); if (selected != null) { _controller.onGenderSelected(selected); _controller.update(); } } // Role popup menu void _showRolePopup(BuildContext context) async { final selected = await showMenu( context: context, position: _popupMenuPosition(context), items: _controller.roles.map((role) { return PopupMenuItem( value: role['id'], child: Text(role['name']), ); }).toList(), ); if (selected != null) { _controller.onRoleSelected(selected); _controller.update(); } } RelativeRect _popupMenuPosition(BuildContext context) { final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox; return RelativeRect.fromLTRB(100, 300, overlay.size.width - 100, 0); } }