import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; import 'package:test_sa/controllers/validator/validator.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/modules/signup/models/company_model.dart'; import 'package:test_sa/modules/signup/models/group_model.dart'; import 'package:test_sa/modules/signup/models/signup_request_model.dart'; import 'package:test_sa/modules/signup/models/site_model.dart'; import 'package:test_sa/modules/signup/models/department_model.dart'; import 'package:test_sa/modules/signup/models/employee_erp_model.dart'; import 'package:test_sa/modules/signup/providers/company_provider.dart'; import 'package:test_sa/modules/signup/providers/group_provider.dart'; import 'package:test_sa/modules/signup/providers/signup_provider.dart'; import 'package:test_sa/modules/signup/providers/signup_site_provider.dart'; import 'package:test_sa/modules/signup/providers/signup_department_provider.dart'; import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/common_widgets/app_filled_button.dart'; import 'package:test_sa/new_views/common_widgets/app_lazy_loading.dart'; import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/single_item_drop_down_menu.dart'; class SignUpScreen extends StatefulWidget { static const String routeName = "/signup_screen"; const SignUpScreen({Key? key}) : super(key: key); @override State createState() => _SignUpScreenState(); } class _SignUpScreenState extends State { final GlobalKey _formKey = GlobalKey(); late AssetGroupProvider _assetGroupProvider; late CompanyProvider _companyProvider; late SignUpProvider _signUpProvider; late SignupSiteProvider _siteProvider; late SignupDepartmentProvider _departmentProvider; // Form field controllers final TextEditingController _employeeIdController = TextEditingController(); final TextEditingController _fullNameController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _mobileController = TextEditingController(); final TextEditingController _extensionController = TextEditingController(); final TextEditingController _roleController = TextEditingController(); // Selected values AssetGroup? _selectedAssetGroup; Company? _selectedCompany; SiteModel? _selectedSite; DepartmentModel? _selectedDepartment; EmployeeERPModel? _employeeERPData; // Store the ERP employee data bool _isHMGGroup = false; bool _employeeFetched = false; bool _isSubmitting = false; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _assetGroupProvider.getData(); }); } @override void dispose() { _employeeIdController.dispose(); _fullNameController.dispose(); _emailController.dispose(); _mobileController.dispose(); _extensionController.dispose(); _roleController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { _assetGroupProvider = Provider.of(context); _companyProvider = Provider.of(context); _signUpProvider = Provider.of(context); _siteProvider = Provider.of(context); _departmentProvider = Provider.of(context); return Scaffold( backgroundColor: AppColor.scaffoldBackground(context), appBar: const DefaultAppBar(title: "Sign Up"), body: Column( children: [ Expanded( child: Form( key: _formKey, child: SingleChildScrollView( padding: EdgeInsets.all(16.toScreenWidth), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildAssetGroupDropdown(), 16.height, if (_selectedAssetGroup != null) ...[ _buildCompanyDropdown(), 16.height, ], if (_selectedCompany != null) ..._buildDynamicFields(), ], ), ), ), ), if (_selectedCompany != null) Container( padding: EdgeInsets.all(16.toScreenWidth), decoration: BoxDecoration( color: AppColor.background(context), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, -2), ), ], ), child: SafeArea( child: _buildSubmitButton(), ), ), ], ), ); } Widget _buildAssetGroupDropdown() { return SingleItemDropDownMenu( context: context, title: "Asset Group", initialValue: _selectedAssetGroup, showAsFullScreenDialog: false, showAsBottomSheet: true, onSelect: (value) { setState(() { _selectedAssetGroup = value; _selectedCompany = null; _clearForm(); }); if (value?.id != null) { _companyProvider.getData(id: value!.id); // Clear sites and departments when asset group changes _signUpProvider.reset(); // Clear sites and departments when asset group changes _signUpProvider.reset(); } }, validator: (value) { if (value == null) return "Asset Group is required"; return null; }, ); } Widget _buildCompanyDropdown() { return SingleItemDropDownMenu( context: context, title: "Company", initialValue: _selectedCompany, showAsFullScreenDialog: false, showAsBottomSheet: true, onSelect: (value) { setState(() { _selectedCompany = value; _isHMGGroup = value?.companyName?.toUpperCase() == 'HMG'; _employeeFetched = false; _clearForm(); }); // Reset and fetch site and department data when company is selected if (_selectedAssetGroup?.id != null) { _siteProvider.reset(); _departmentProvider.reset(); _siteProvider.getData(id: _selectedAssetGroup!.id); _departmentProvider.getData(id: _selectedAssetGroup!.id); } }, validator: (value) { if (value == null) return "Company is required"; return null; }, ); } List _buildDynamicFields() { if (_isHMGGroup) { return [ _buildEmployeeIdField(), 16.height, if (_employeeFetched) ...[ _buildReadOnlyField("Full Name", _fullNameController), 16.height, _buildReadOnlyField("Email Address", _emailController), 16.height, _buildReadOnlyField("Mobile Number", _mobileController), 16.height, _buildExtensionField(), 16.height, _buildSiteDropdown(), 16.height, _buildDepartmentDropdown(), 16.height, _buildRoleField(), ], ]; } else { return [ // Employee ID is auto-generated for Non-HMG, so not shown during signup _buildFullNameField(), 16.height, _buildEmailField(), 16.height, _buildMobileField(), 16.height, _buildExtensionField(), 16.height, _buildSiteDropdown(), 16.height, _buildDepartmentDropdown(), 16.height, _buildRoleField(), ]; } } Widget _buildEmployeeIdField() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: AppTextFormField( controller: _employeeIdController, labelText: "Employee ID", hintText: "Enter Employee ID", textInputType: TextInputType.number, validator: (value) { if (value == null || value.isEmpty) return "Employee ID is required"; if (!Validator.isNumeric(value)) return "Employee ID must be numeric"; return null; }, ), ), 12.width, Container( margin: EdgeInsets.only(top: 8.toScreenHeight), child: AppFilledButton( label: "Search", height: 48, width: 100, loading: _signUpProvider.loading, disableButton: _signUpProvider.loading, onPressed: () { if (_employeeIdController.text.isEmpty) { Fluttertoast.showToast(msg: "Please enter Employee ID"); return; } if (!Validator.isNumeric(_employeeIdController.text)) { Fluttertoast.showToast(msg: "Employee ID must be numeric"); return; } _fetchEmployeeDetails(_employeeIdController.text); }, ), ), ], ); } Widget _buildReadOnlyField(String label, TextEditingController controller) { return AppTextFormField( controller: controller, labelText: label, enable: false, backgroundColor: AppColor.disableFieldBackground(context), ); } Widget _buildFullNameField() { return AppTextFormField( controller: _fullNameController, labelText: "Full Name", hintText: "Enter Full Name", validator: (value) { if (value == null || value.isEmpty) return "Full Name is required"; return null; }, ); } Widget _buildEmailField() { return AppTextFormField( controller: _emailController, labelText: "Email Address", hintText: "Enter Email Address", textInputType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) return "Email is required"; if (!Validator.isEmail(value)) return "Invalid email format"; return null; }, ); } Widget _buildMobileField() { return AppTextFormField( controller: _mobileController, labelText: "Mobile Number", hintText: "Enter Mobile Number", textInputType: TextInputType.phone, validator: (value) { if (value == null || value.isEmpty) return "Mobile Number is required"; if (!Validator.isPhoneNumber(value)) return "Invalid mobile number"; return null; }, ); } Widget _buildExtensionField() { return AppTextFormField( controller: _extensionController, labelText: "Extension Number", hintText: "Enter Extension Number (Optional)", textInputType: TextInputType.number, validator: (value) { if (value != null && value.isNotEmpty && !Validator.isNumeric(value)) { return "Extension must be numeric"; } return null; }, ); } Widget _buildSiteDropdown() { return SingleItemDropDownMenu( context: context, title: "Site", initialValue: _selectedSite, showAsFullScreenDialog: false, showAsBottomSheet: true, requestById: _selectedAssetGroup?.id, onSelect: (value) { setState(() { _selectedSite = value; }); // No need to fetch departments when site changes - they are independent }, validator: (value) { if (value == null) return "Site is required"; return null; }, ); } Widget _buildDepartmentDropdown() { return SingleItemDropDownMenu( context: context, title: "Department", initialValue: _selectedDepartment, showAsFullScreenDialog: false, showAsBottomSheet: true, requestById: _selectedAssetGroup?.id, onSelect: (value) { setState(() { _selectedDepartment = value; }); }, validator: (value) { if (value == null) return "Department is required"; return null; }, ); } Widget _buildRoleField() { return AppTextFormField( controller: _roleController, labelText: "Role", hintText: "Enter Role", validator: (value) { if (value == null || value.isEmpty) return "Role is required"; return null; }, ); } Widget _buildSubmitButton() { return AppFilledButton( label: "Submit", maxWidth: true, loading: _isSubmitting, disableButton: _isSubmitting, onPressed: _submitForm, ); } Future _fetchEmployeeDetails(String employeeId) async { final employee = await _signUpProvider.getEmployeeFromERP(employeeId); if (employee != null) { // Check if the error message indicates duplicate account if (_signUpProvider.errorMessage != null && _signUpProvider.errorMessage!.toLowerCase().contains('already')) { // Show duplicate account popup _showDuplicateAccountDialog(); setState(() { _employeeFetched = false; _employeeERPData = null; _employeeIdController.clear(); }); return; } setState(() { _employeeFetched = true; _employeeERPData = employee; // Store the ERP data for later use _fullNameController.text = employee.employeeName ?? ''; _emailController.text = employee.employeeEmailAddress ?? ''; _mobileController.text = employee.employeeMobileNumber ?? ''; }); } else { // Check if it's a duplicate account error if (_signUpProvider.errorMessage != null && (_signUpProvider.errorMessage!.toLowerCase().contains('already') || _signUpProvider.errorMessage!.toLowerCase().contains('exists') || _signUpProvider.errorMessage!.toLowerCase().contains('account'))) { _showDuplicateAccountDialog(); setState(() { _employeeFetched = false; _employeeERPData = null; _employeeIdController.clear(); }); } else { setState(() { _employeeFetched = false; _employeeERPData = null; }); Fluttertoast.showToast( msg: _signUpProvider.errorMessage ?? "Failed to fetch employee details", ); } } } void _showDuplicateAccountDialog() { showDialog( context: context, builder: (context) => AlertDialog( backgroundColor: AppColor.background(context), title: "Account Exists".bodyText(context), content: "Already you have an account on Atoms".bodyText(context), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: "OK".bodyText(context).custom(color: AppColor.primary10), ), ], ), ); } void _clearForm() { _employeeIdController.clear(); _fullNameController.clear(); _emailController.clear(); _mobileController.clear(); _extensionController.clear(); _roleController.clear(); _selectedSite = null; _selectedDepartment = null; _employeeFetched = false; _employeeERPData = null; } Future _submitForm() async { // Validate form fields if (!_formKey.currentState!.validate()) { Fluttertoast.showToast(msg: "Please fill all required fields"); return; } // HMG Group specific validations if (_isHMGGroup) { // Employee ID is mandatory for HMG if (_employeeIdController.text.isEmpty) { Fluttertoast.showToast(msg: "Employee ID is required"); return; } // Employee must be fetched from ERP if (!_employeeFetched) { Fluttertoast.showToast(msg: "Please search and fetch employee details from ERP"); return; } // Validate Employee ID is numeric if (!Validator.isNumeric(_employeeIdController.text)) { Fluttertoast.showToast(msg: "Employee ID must be numeric"); return; } // Site is mandatory for HMG if (_selectedSite == null) { Fluttertoast.showToast(msg: "Site is required"); return; } // Department is mandatory for HMG if (_selectedDepartment == null) { Fluttertoast.showToast(msg: "Department is required"); return; } } else { // Non-HMG specific validations // Full Name is mandatory if (_fullNameController.text.isEmpty) { Fluttertoast.showToast(msg: "Full Name is required"); return; } // Email is mandatory and must be valid format if (_emailController.text.isEmpty) { Fluttertoast.showToast(msg: "Email Address is required"); return; } if (!Validator.isEmail(_emailController.text)) { Fluttertoast.showToast(msg: "Please enter a valid email address"); return; } // Mobile Number is mandatory and must be numeric if (_mobileController.text.isEmpty) { Fluttertoast.showToast(msg: "Mobile Number is required"); return; } if (!Validator.isPhoneNumber(_mobileController.text)) { Fluttertoast.showToast(msg: "Please enter a valid mobile number"); return; } // Site is mandatory for Non-HMG if (_selectedSite == null) { Fluttertoast.showToast(msg: "Site is required"); return; } // Department is mandatory for Non-HMG if (_selectedDepartment == null) { Fluttertoast.showToast(msg: "Department is required"); return; } } // Common validations for both HMG and Non-HMG // Extension Number validation (optional but must be numeric if provided) if (_extensionController.text.isNotEmpty && !Validator.isNumeric(_extensionController.text)) { Fluttertoast.showToast(msg: "Extension Number must be numeric"); return; } // Role is mandatory if (_roleController.text.isEmpty) { Fluttertoast.showToast(msg: "Role is required"); return; } // Validate Asset Group is selected if (_selectedAssetGroup == null) { Fluttertoast.showToast(msg: "Asset Group is required"); return; } // Validate Company is selected if (_selectedCompany == null) { Fluttertoast.showToast(msg: "Company is required"); return; } setState(() { _isSubmitting = true; }); if (mounted) { showDialog( context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading(), ); } // Build request with conditional logic based on isHMGGroup final request = SignUpRequestModel( assetGroupId: _selectedAssetGroup?.id, companyId: _selectedCompany?.id, employeeId: _isHMGGroup ? _employeeIdController.text : null, fullName: _fullNameController.text, emailAddress: _emailController.text, mobileNumber: _mobileController.text, extensionNumber: _extensionController.text.isEmpty ? null : _extensionController.text, // For HMG: send both selected IDs and ERP data siteId: _selectedSite?.id, erpSite: _isHMGGroup ? _employeeERPData?.branchCode : null, departmentId: _selectedDepartment?.id, erpDepartment: _isHMGGroup ? _employeeERPData?.branchName : null, role: _roleController.text, isFromERP: _isHMGGroup, ); final success = await _signUpProvider.submitSignUpRequest(request); if (mounted) { Navigator.pop(context); // Close loading dialog } setState(() { _isSubmitting = false; }); if (success) { if (mounted) { _showSuccessDialog(); } } else { Fluttertoast.showToast( msg: _signUpProvider.errorMessage ?? "Failed to submit signup request", ); } } void _showSuccessDialog() { showDialog( context: context, builder: (context) => AlertDialog( backgroundColor: AppColor.background(context), title: "Success".bodyText(context), content: "Your signup request has been submitted successfully. It will be reviewed by the Human Resources Admin." .bodyText(context), actions: [ TextButton( onPressed: () { Navigator.pop(context); // Close dialog Navigator.pop(context); // Go back to login }, child: "OK".bodyText(context).custom(color: AppColor.primary10), ), ], ), ); } }