import 'dart:convert'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import '../config/environment.dart'; import '../customAppBar/toastHelper.dart'; import '../responsive.dart'; import '../service/api_service.dart'; import '../service/file_upload_service.dart'; import 'package:http/http.dart' as http; import 'package:file_picker/file_picker.dart'; import '../service/multi_file_upload_widget.dart'; import '../service/token_storage_service.dart'; import 'package:pdf/widgets.dart' as pw; class RaiseClaimDialog extends StatefulWidget { final BuildContext parentContext; final VoidCallback onSuccess; const RaiseClaimDialog({Key? key, required this.parentContext, required this.onSuccess,}) : super(key: key); @override State createState() => _RaiseClaimDialogState(); } class _RaiseClaimDialogState extends State { // const RaiseClaimDialog({super.key}); late ApiService apiService; bool isLoading = false; dynamic empPrimaryId; dynamic empClientId; dynamic empClientBranchId; dynamic empHrId; final tokenService = TokenStorageService(); String? _postPreToken = ''; List> policyList = []; dynamic policyDataIsEmpty = 1; dynamic policyHeading; dynamic policyName; dynamic EmployeePolicy; List> employeeDetails = []; dynamic argumentsData; dynamic claimsDetails; int? fromClaimsPage; dynamic decodedToken; List> departmentList = []; List> policyNumberList = []; int? serviceId; String? serviceName; int? policyNumberId; int? selectedMemberId; String? selectedMemberName; String? selectedServiceName; String? selectedPolicyNo; dynamic claimsDepartmentId; dynamic claimSubject; dynamic rawPolicyStartDate; dynamic rawPolicyEndDate; dynamic claimsPolicyNo; dynamic client_branch_id; dynamic mobileNo; dynamic client_policy_id; dynamic selfDetails; dynamic emailId; List> employeePolicyList = []; String? selectedFileNames; // html.File? uploadedFile; // List uploadedFiles = []; List uploadedFiles = []; final fileService = FileUploadService(); bool isSubmitting = false; dynamic getPostCardArrays = []; List> activePoliciesList = []; int stausVal = 1; Map getClaimPoliciesApi = {}; int? selectedPolicyTypeId; int? selectedClientPolicyId; Map? selectedMemberObject; // Declare subjectController and bodyController as instance variables late TextEditingController subjectController; late TextEditingController messageController; late TextEditingController accidentDetailsController; late TextEditingController hospitalNameController; late TextEditingController hospitalAddressController; late TextEditingController hospitalCityController; late TextEditingController hospitalStateController; late TextEditingController hospitalPinCodeController; late TextEditingController hospitalPhoneNoController; late TextEditingController claimAmountController; late TextEditingController sumInsuredController; late TextEditingController admitDateController; late TextEditingController dischargeDateController; DateTime? accidentDate; DateTime? deathDate; DateTime? intimationDate; DateTime? birthDate; DateTime? admitDate; DateTime? dischargeDate; DateTime? parsedPolicyStartDate; DateTime? parsedPolicyEndDate; Map selectedDates = { "Accident Date": null, "Date of Death": null, }; final Map> servicePolicyTypeMap = { 1: [2, 3, 4, 5], 2: [1], 3: [6], 4: [7], }; List> filteredPoliciesList = []; // Create a unique form key for each accordion section final GlobalKey formKey = GlobalKey(); bool isServiceValid = true; bool isPolicyValid = true; bool isMemberValid = true; bool isSubjectValid = true; bool isHospitalNameValid = true; bool isHospitalAddressValid = true; bool isHospitalCityValid = true; bool isHospitalStateValid = true; bool isHospitalPincodeValid = true; bool isHospitalPhoneNoValid = true; bool isAdmitDischargeValid = true; bool isClaimAmountValid = true; bool isAccidentDateValid = true; bool isIntimationDateValid = true; bool isAdmitDateValid = true; bool isDischargeDateValid = true; @override void initState() { super.initState(); fileService.clearAll(); subjectController = TextEditingController(); messageController = TextEditingController(); accidentDetailsController = TextEditingController(); hospitalNameController = TextEditingController(); hospitalAddressController = TextEditingController(); hospitalCityController = TextEditingController(); hospitalStateController = TextEditingController(); hospitalPinCodeController = TextEditingController(); hospitalPhoneNoController = TextEditingController(); claimAmountController = TextEditingController(); sumInsuredController = TextEditingController(); admitDateController = TextEditingController(); dischargeDateController = TextEditingController(); apiService = ApiService(context); // Initialize ApiService here _loadToken(); // Check if fromClaimsPage is 0 and set serviceId to 'Claims' (id is 2) // if (fromClaimsPage == 0) { // setInitialServiceId(); // } } @override void dispose() { // Dispose the controllers to avoid memory leaks subjectController.dispose(); messageController.dispose(); accidentDetailsController.dispose(); hospitalNameController.dispose(); hospitalAddressController.dispose(); hospitalCityController.dispose(); hospitalStateController.dispose(); hospitalPinCodeController.dispose(); hospitalPhoneNoController.dispose(); claimAmountController.dispose(); sumInsuredController.dispose(); admitDateController.dispose(); dischargeDateController.dispose(); serviceId = null; departmentList.clear(); super.dispose(); fileService.clearAll(); } Future _loadToken() async { _postPreToken = tokenService.getCurrentToken(); empClientId = await tokenService.readValue('empClientId'); empClientBranchId = await tokenService.readValue('empClientBranchId'); empHrId = await tokenService.readValue('empHrId'); getClaimsPoliciesDetails(); await getPostCashDepositDetails( empClientBranchId, empClientId, empHrId, _postPreToken); } Future getClaimsPoliciesDetails() async { print('9'); setState(() { isLoading = true; }); try { print('10'); final response = await apiService.getClaimPoliciesToApi(_postPreToken!); if (response['status'] == 'success') { setState(() { isLoading = false; }); setState(() { getClaimPoliciesApi = Map.from(response['data']); departmentList = (getClaimPoliciesApi['ticket_type'] as List) .map>((item) => { 'id': int.parse(item['ticket_type'].toString()), 'name': item['type_name'].toString(), }) .toList(); }); } else { setState(() { isLoading = false; }); // ToastHelper.showWarningToast( // context, 'Request failed with status: ${response.statusCode}'); print('Request failed with status: ${response['code']}'); } } catch (e) { setState(() { // isLoading = false; }); print('Exception occurred: $e'); } finally { setState(() { // _isLoading = false; }); } } Future getPostCashDepositDetails( empClientBranchId, empClientId, empHrId, _postPreToken) async { print('IN'); print("clintBranchId -$empClientBranchId"); print("clintID -$empClientId"); print("hr_id -$empHrId"); print("token -$_postPreToken"); isLoading = true; // setState(() { // _isLoading = true; // }); try { if (empClientBranchId == null || empClientId == null) { return; } final response = await apiService.getActiveCashDepositDetailsToApi( empClientId!, empClientBranchId!, empHrId, _postPreToken, stausVal); // final response = await apiService.getCashDepositDetailsToApi( // clintID!, clintBranchId!, hr_id, token); print('IN1'); if (response['status'] == 'success') { isLoading = false; setState(() { print('response'); print(response['data']); getPostCardArrays = List>.from(response['data']); print('getPostCardArrays'); print(getPostCardArrays); activePoliciesList = getPostCardArrays; }); print('IN2'); } else { isLoading = false; print('API request failed with status'); setState(() { activePoliciesList = []; }); print('API request failed with status'); } } catch (e) { print('Exception occurred: $e'); } } void filterPoliciesByService(int serviceTicketType) { final allowedPolicyTypes = servicePolicyTypeMap[serviceTicketType] ?? []; final filtered = activePoliciesList.where((policy) { final policyTypeId = int.tryParse( policy['policy_type_id'].toString(), ); return allowedPolicyTypes.contains(policyTypeId); }).toList(); setState(() { policyNumberId = null; policyNumberList = filtered.map>((policy) { return { // ✅ VALUE (what gets sent) 'id': int.parse(policy['client_policy_id'].toString()), // ✅ DISPLAY (what user sees) 'label': '${policy['type']} - ${policy['policy_no']}', // keep extras if needed 'policy_type_id': int.parse(policy['policy_type_id'].toString()), }; }).toList(); isPolicyValid = true; }); } Future getCDPoliciesDetails() async { print('9'); setState(() { isLoading = true; }); try { print('10'); final response = await apiService.getEmployeeAndDependenceToApi( empClientId, selectedClientPolicyId, empClientBranchId, _postPreToken!); if (response['status'] == 'success') { final List> members = List>.from(response['data']); setState(() { employeePolicyList = members.map((m) { return { 'id': int.parse(m['id'].toString()), // ✅ UNIQUE 'name': m['name'], // ✅ DISPLAY 'client_policy_id': m['client_policy_id'] ?? '', 'emp_id': m['self_employee_id'] ?? '', 'insured_emp_id': m['employee_id'] ?? '', 'emp_code': m['emp_code'] ?? '', 'mobile': m['mobile'] ?? ' ', 'empEmailCorporate': m['email_corporate'] ?? '', 'relationship': m['relationship'], 'gender': m['gender'], 'dob': m['dob'], 'policy_name': serviceId == 1 ? null : m['policy_name'], }; }).toList(); }); } } catch (e) { setState(() { isLoading = false; }); print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } Future sendFormDataToApi() async { setState(() { isServiceValid = serviceId != null; isPolicyValid = selectedClientPolicyId != null; isMemberValid = selectedMemberId != null; // isSubjectValid = subjectController.text.trim().isNotEmpty; // 🏥 GMC / Topup final isGmc = serviceId == 1 || serviceId == 4; isHospitalNameValid = !isGmc || hospitalNameController.text.trim().isNotEmpty; isHospitalAddressValid = !isGmc || hospitalAddressController.text.trim().isNotEmpty; isHospitalCityValid = !isGmc || hospitalCityController.text.trim().isNotEmpty; isHospitalStateValid = !isGmc || hospitalStateController.text.trim().isNotEmpty; isHospitalPincodeValid = !isGmc || hospitalPinCodeController.text.trim().isNotEmpty; isHospitalPhoneNoValid = !isGmc || hospitalPhoneNoController.text.trim().isNotEmpty; isAdmitDateValid = !isGmc || admitDate != null; isDischargeDateValid = !isGmc || dischargeDate != null; isClaimAmountValid = !isGmc || claimAmountController.text.trim().isNotEmpty; // ☠ Accident / Death final isAccident = [2, 3, 4].contains(serviceId); isAccidentDateValid = !isAccident || accidentDate != null; isIntimationDateValid = !isAccident || intimationDate != null; }); if (isServiceValid && isPolicyValid && isMemberValid && // isSubjectValid && isHospitalNameValid && isHospitalAddressValid && isHospitalStateValid && isHospitalCityValid && isHospitalPincodeValid && isHospitalPhoneNoValid && isAdmitDateValid && isDischargeDateValid && isClaimAmountValid && isAccidentDateValid && isIntimationDateValid) { if (FileUploadService().files.isEmpty) { setState(() { MultiFileUploadWidget.hasFiles = false; }); ToastHelper.showErrorToast(context, 'Please upload at least one document'); return; } // Proceed to submit } else { ToastHelper.showErrorToast(context, 'Please Fill Required Fields'); return; } setState(() => isSubmitting = true); // 🔥 start loader setState(() { isLoading = true; }); try { print('Check One'); Map fields = { 'client_policy_id': selectedClientPolicyId, // 'policy_type_id': selectedPolicyTypeId, 'emp_id': selectedMemberObject?['emp_id'], 'ticket_type_id': serviceId, 'subject': serviceName, 'message': messageController.text, 'emp_code': selectedMemberObject?['emp_code'] ?? '', 'mobile_number': selectedMemberObject?['mobile'] ?? ' ', 'email': selectedMemberObject?['empEmailCorporate'] ?? '', 'fullname': selectedMemberObject?['name'] ?? '', 'client_id': empClientId, 'relationship': selectedMemberObject?['relationship'], 'gender': selectedMemberObject?['gender'], 'age': selectedMemberObject?['dob'], 'policy_name': serviceId == 1 ? null : selectedMemberObject?['policy_name'], }; if (serviceId == 1 || serviceId == 72) { String formattedAdmitDate = DateFormat('yyyy-MM-dd').format(admitDate!); String formattedDischargeDate = DateFormat('yyyy-MM-dd').format(dischargeDate!); fields['hospital_name'] = hospitalNameController.text; fields['hospital_address'] = hospitalAddressController.text; fields['hospital_city'] = hospitalCityController.text; fields['hospital_state'] = hospitalStateController.text; fields['hospital_pin_code'] = hospitalPinCodeController.text; fields['hospital_phone_no'] = hospitalPhoneNoController.text; fields['doa'] = formattedAdmitDate; fields['dod'] = formattedDischargeDate; fields['claim_amount'] = claimAmountController.text; fields['policyholder_name'] = employeePolicyList[0]['name']; fields['member_name'] = selectedMemberObject?['name']; fields['insured_emp_id'] = selectedMemberObject?['insured_emp_id']; } else { String formattedAccidentDate = DateFormat('yyyy-MM-dd').format(accidentDate!); String formattedDeathDate = DateFormat('yyyy-MM-dd').format(deathDate!); String formattedBirthDate = DateFormat('yyyy-MM-dd').format(birthDate!); String formattedIntimationDate = DateFormat('yyyy-MM-dd').format(intimationDate!); fields['date_of_accident'] = formattedAccidentDate; fields['dob'] = formattedBirthDate; fields['date_of_intimat'] = formattedIntimationDate; fields['date_of_death'] = formattedDeathDate; fields['si_amt'] = sumInsuredController.text; fields['policyholder_name'] = employeePolicyList[0]['name']; fields['member_name'] = selectedMemberName; fields['insured_emp_id'] = selectedMemberObject?['insured_emp_id']; } final request = http.MultipartRequest('POST', Uri.parse('${Environment.apiUrlPost}initiateClaim')); request.headers['Authorization'] = 'Bearer $_postPreToken'; request.headers['APP-SIGNATURE'] = 'nhance-2025-signature-T8f6gV9k5fK2wf5V5c4vId3b0J8z6cAm2x8Y'; final stringFields = fields.map((key, value) => MapEntry(key, value?.toString() ?? '')); request.fields.addAll(stringFields); // get uploaded files final uploadedFiles = FileUploadService().files; print("📁 Total uploaded files: ${uploadedFiles.length}"); print("📂 File list (original names): ${uploadedFiles.map((f) => f.file.name).toList()}"); // Validate all labels present (optional but recommended) for (final uf in uploadedFiles) { print("📝 Checking label for file: ${uf.file.name}, current label: '${uf.label}'"); if ((uf.label ?? '').trim().isEmpty) { ToastHelper.showErrorToast(context, 'Please enter name for all uploaded documents'); setState(() => isLoading = false); return; } } // ✅ NEW VALIDATION: At least one PDF must be uploaded // bool hasPdf = uploadedFiles.any((uf) { // final ext = uf.file.extension?.toLowerCase() ?? ''; // return ext == 'pdf'; // }); // // if (!hasPdf) { // ToastHelper.showErrorToast(context, 'Please upload at least one PDF document'); // setState(() => isLoading = false); // return; // } // Add files // for (var uf in uploadedFiles) { // final pf = uf.file; // if (pf.bytes != null) { // request.files.add(http.MultipartFile.fromBytes( // 'claim_docs[]', // pf.bytes!, // filename: pf.name, // )); // } // } // Add files — convert images to PDF if needed for (var uf in uploadedFiles) { final pf = uf.file; final ext = pf.extension?.toLowerCase() ?? ''; if (pf.bytes != null) { Uint8List fileBytes = pf.bytes!; if (['jpg', 'jpeg', 'png', 'heic'].contains(ext)) { // ✅ Convert image → PDF final pdf = pw.Document(); final image = pw.MemoryImage(fileBytes); pdf.addPage( pw.Page( build: (pw.Context context) => pw.Center( child: pw.Image(image, fit: pw.BoxFit.contain), ), ), ); fileBytes = await pdf.save(); // converted PDF bytes // replace file name with .pdf extension final pdfFileName = pf.name.replaceAll(RegExp(r'\.\w+$'), '.pdf'); print('📄 Converted image ${pf.name} → PDF ($pdfFileName)'); request.files.add(http.MultipartFile.fromBytes( 'claim_docs[]', fileBytes, filename: pdfFileName, )); } else { // ✅ Already a PDF request.files.add(http.MultipartFile.fromBytes( 'claim_docs[]', fileBytes, filename: pf.name, )); } } } // ✅ Combine all names into a JSON array string final claimDocNames = uploadedFiles.map((uf) => uf.label.trim()).toList(); final encodedNames = jsonEncode(claimDocNames); request.fields['claim_doc_names'] = encodedNames; // ✅ Debug print print("Payload being sent:"); print("Files: ${uploadedFiles.map((f) => f.file.name).toList()}"); print("Names (JSON): $encodedNames"); final response = await request.send(); final responseBody = await response.stream.bytesToString(); final decoded = jsonDecode(responseBody); if (decoded['status'] == true) { // 1️⃣ Close dialog first Navigator.pop(context); // 2️⃣ Call parent page function widget.onSuccess(); ToastHelper.showSuccessToast(context, decoded['message']); serviceId = null; departmentList.clear(); setState(() { isLoading = false; }); // context.go('/claims', extra: 2); print('Form data submitted successfully'); fileService.clearAll(); } else { setState(() { isLoading = false; }); Navigator.pop(context); ToastHelper.showErrorToast(context, "Failed: ${decoded['message']}"); } } catch (e) { setState(() { isLoading = false; }); print('Error submitting form data: $e'); } finally { setState(() => isSubmitting = false); // 🔥 stop loader } } Future _pickDate(BuildContext context, String label) async { final DateTime? pickedDate = await showDatePicker( context: context, initialDate: selectedDates[label] ?? DateTime.now(), firstDate: DateTime(2000), lastDate: DateTime.now(), ); if (pickedDate != null && pickedDate != selectedDates[label]) { setState(() { selectedDates[label] = pickedDate; }); } } Future _pickFromToDate(BuildContext context) async { // Define the policy date range final DateTime policyStartDate = DateFormat('dd-MMM-yyyy').parse(rawPolicyStartDate); final DateTime policyEndDate = DateFormat('dd-MMM-yyyy').parse(rawPolicyEndDate); // Show the date range picker within the policy date limits final DateTimeRange? pickedDateRange = await showDateRangePicker( context: context, firstDate: policyStartDate, lastDate: policyEndDate, initialDateRange: admitDate != null && dischargeDate != null ? DateTimeRange(start: admitDate!, end: dischargeDate!) : null, ); // Update values if a valid date range is picked if (pickedDateRange != null) { setState(() { admitDate = pickedDateRange.start; dischargeDate = pickedDateRange.end; admitDateController.text = DateFormat('dd-MM-yyyy').format(admitDate!); dischargeDateController.text = DateFormat('dd-MM-yyyy').format(dischargeDate!); }); } } // Future _pickFromToDate(BuildContext context) async { // final DateTimeRange? pickedDateRange = await showDateRangePicker( // context: context, // firstDate: DateTime(2000), // lastDate: DateTime(2100), // initialDateRange: admitDate != null && dischargeDate != null // ? DateTimeRange(start: admitDate!, end: dischargeDate!) // : null, // ); // // if (pickedDateRange != null) { // setState(() { // admitDate = pickedDateRange.start; // dischargeDate = pickedDateRange.end; // admitDateController.text = DateFormat('yyyy-MM-dd').format(admitDate!); // dischargeDateController.text = // DateFormat('yyyy-MM-dd').format(dischargeDate!); // }); // } // } int calculateAge(String dob) { DateTime birthDate = DateTime.parse(dob); // Parse the dob string DateTime currentDate = DateTime.now(); int age = currentDate.year - birthDate.year; // Adjust age if the birthday has not occurred yet this year if (currentDate.month < birthDate.month || (currentDate.month == birthDate.month && currentDate.day < birthDate.day)) { age--; } return age; } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.white, // ✅ PURE WHITE popup insetPadding: const EdgeInsets.all(20), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: ClipRRect( borderRadius: BorderRadius.circular(16), child: SizedBox( width: MediaQuery.of(context).size.width * 0.75, // Desktop popup width // height: MediaQuery.of(context).size.height * 0.85, child: Stack( children: [ /// MAIN CONTENT (YOUR EXISTING UI) SingleChildScrollView( child: Container( padding: EdgeInsets.all(20), color: Colors.white, child: Column( children: [ /// 🔹 HEADER ROW (Title + Close) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Raise Insurance Claim", style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w600, ), ), IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context), ), ], ), const SizedBox(height: 16), Form( key: formKey, child: Column( children: [ _row([ buildDropdownField( 'Service', (value) { final selectedItem = departmentList.firstWhere( (item) => item['id'] == value, orElse: () => {}, ); setState(() { serviceId = value; serviceName = selectedItem['name']; policyNumberId = null; isServiceValid = true; }); print('🔥 serviceId set to $serviceId'); filterPoliciesByService(value!); }, departmentList, 'name', serviceId, ), buildDropdownField( 'Select Policy', (value) { final selectedPolicy = policyNumberList.firstWhere((p) => p['id'] == value); setState(() { // ✅ THIS is what you send to API selectedClientPolicyId = selectedPolicy['id']; // optional selectedPolicyTypeId = selectedPolicy['policy_type_id']; policyNumberId = value; isPolicyValid = true; }); getCDPoliciesDetails(); }, policyNumberList, 'label', // 👈 DISPLAY FIELD policyNumberId, ), buildDropdownFieldSearch( 'Member Name', (value) { final member = employeePolicyList.firstWhere( (m) => m['id'] == value, ); setState(() { selectedMemberId = value; selectedMemberObject = member; // ✅ FULL OBJECT selectedMemberName = member['name']; isMemberValid = true; print('selectedMemberObject $selectedMemberObject'); }); }, employeePolicyList, 'name', selectedMemberId, ), ]), _row([ buildTextField('Message', messageController), if (serviceId == 1 || serviceId == 72)...[ buildTextField('Hospital Name', hospitalNameController), buildTextField('Hospital Address', hospitalAddressController), ] ]), if (serviceId == 1 || serviceId == 72) _row([ buildTextField('Hospital City', hospitalCityController), buildTextField('Hospital State', hospitalStateController), buildTextField( 'Hospital Pincode', hospitalPinCodeController, keyboardType: TextInputType.number, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(6), ], ), ]), if (serviceId == 1 || serviceId == 72) _row([ buildTextField( 'Hospital Phone No', hospitalPhoneNoController, keyboardType: TextInputType.number, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], ), buildDatePickerField( label: 'Admit Date', selectedDate: admitDate, allowFuture: false, onDateSelected: (d) { setState(() { admitDate = d; dischargeDate = null; }); }, ), buildDatePickerField( label: 'Discharge Date', selectedDate: dischargeDate, allowFuture: true, minDate: admitDate?.add(const Duration(days: 1)), onDateSelected: (d) => setState(() => dischargeDate = d), ), buildTextField( 'Claims Amount', claimAmountController, keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.digitsOnly], ), ]), if ([2, 3, 4].contains(serviceId)) _row([ buildDatePickerField( label: 'Date of Birth', selectedDate: birthDate, allowFuture: false, onDateSelected: (d) => setState(() => birthDate = d), ), buildDatePickerField( label: 'Accident Date', selectedDate: accidentDate, allowFuture: false, onDateSelected: (d) { setState(() { accidentDate = d; deathDate = null; intimationDate = null; }); }, ), buildDatePickerField( label: 'Date of Death', selectedDate: deathDate, allowFuture: false, onDateSelected: (d) => setState(() => deathDate = d), ), ]), if ([2, 3, 4].contains(serviceId)) _row([ buildDatePickerField( label: 'Date of Intimation', selectedDate: intimationDate, allowFuture: false, onDateSelected: (d) => setState(() => intimationDate = d), ), buildTextField( 'Sum Insured', sumInsuredController, keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.digitsOnly], ), const SizedBox(), ]), _row([ MultiFileUploadWidget(), ]), Align( alignment: Alignment.centerRight, child: SizedBox( width: 120, height: 42, child: ElevatedButton( onPressed: isSubmitting ? null : sendFormDataToApi, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFE26728), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: isSubmitting ? const SizedBox( height: 18, width: 18, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : const Text( 'Send', style: TextStyle(color: Colors.white, fontWeight: FontWeight.w600), ), ), ), ), ], ), ), ], ), ), ), /// 🔄 LOADER OVERLAY (UNCHANGED) if (isLoading) Container( color: const Color(0x98FFFCE5), child: Center( child: Image.asset( 'assets/nhance-loader.gif', height: 60, width: 60, ), ), ), ], ), ), ) ); } /// ---------- HELPERS ---------- Widget _row(List children) { return Padding( padding: const EdgeInsets.only(bottom: 14), child: Row( children: children .map((e) => Expanded( child: Padding( padding: const EdgeInsets.only(right: 12), child: e, ))) .toList(), ), ); } Widget buildTextField( String label, TextEditingController controller, { TextInputType keyboardType = TextInputType.text, List? inputFormatters, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ fieldLabel(label), formBox( child: TextField( controller: controller, keyboardType: keyboardType, inputFormatters: inputFormatters, decoration: const InputDecoration( isDense: true, border: InputBorder.none, ), ), ), ], ); } Widget buildTextAreaField(String label, TextEditingController controller) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ fieldLabel(label), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: const Color(0xFFF1F1F1), borderRadius: BorderRadius.circular(8), ), child: TextField( controller: controller, maxLines: 3, decoration: const InputDecoration( isDense: true, border: InputBorder.none, ), ), ), ], ); } Widget buildDropdownField( String label, void Function(int?) onChanged, List> itemsList, String displayField, int? selectedValue, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ fieldLabel(label), formBox( child: DropdownButtonHideUnderline( child: DropdownButton( isExpanded: true, value: selectedValue, hint: const Text('Select'), icon: const Icon(Icons.keyboard_arrow_down), items: itemsList.map>((item) { return DropdownMenuItem( value: item['id'], child: Text(item[displayField]), ); }).toList(), onChanged: onChanged, ), ), ), ], ); } Widget buildDropdownFieldSearch( String label, void Function(int?) onChanged, List> itemsList, String displayField, int? selectedValue, ) { final TextEditingController searchController = TextEditingController(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ fieldLabel(label), formBox( child: DropdownButtonHideUnderline( child: DropdownButton2( isExpanded: true, value: selectedValue, hint: const Text('Select'), iconStyleData: const IconStyleData( icon: Icon(Icons.keyboard_arrow_down), ), // 🔹 SEARCH CONFIG dropdownSearchData: DropdownSearchData( searchController: searchController, searchInnerWidgetHeight: 50, searchInnerWidget: Padding( padding: const EdgeInsets.all(8), child: TextField( controller: searchController, decoration: InputDecoration( hintText: 'Search...', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), isDense: true, ), ), ), searchMatchFn: (item, searchValue) { return item.value .toString() .toLowerCase() .contains(searchValue.toLowerCase()) || item.child .toString() .toLowerCase() .contains(searchValue.toLowerCase()); }, ), // 🔹 CLEAR SEARCH WHEN CLOSED onMenuStateChange: (isOpen) { if (!isOpen) searchController.clear(); }, items: itemsList.map((item) { return DropdownMenuItem( value: item['id'], child: Text( item[displayField], overflow: TextOverflow.ellipsis, ), ); }).toList(), onChanged: onChanged, ), ), ), ], ); } Widget buildDatePickerField({ required String label, required DateTime? selectedDate, required bool allowFuture, required ValueChanged onDateSelected, DateTime? minDate, DateTime? maxDate, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ fieldLabel(label), formBox( child: InkWell( onTap: () async { final DateTime now = DateTime.now(); final DateTime first = minDate ?? DateTime(1980); final DateTime last = allowFuture ? (maxDate ?? DateTime(2100)) : now; final DateTime initialDate = selectedDate ?? (first.isAfter(now) ? first : now); final picked = await showDatePicker( context: context, initialDate: initialDate, firstDate: first, lastDate: last, ); if (picked != null) { onDateSelected(picked); } }, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( selectedDate != null ? DateFormat('dd-MM-yyyy').format(selectedDate) : 'Select', style: const TextStyle(color: Colors.black), ), const Icon(Icons.calendar_today, size: 18), ], ), ), ), ], ); } // Widget uploadBox() { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // fieldLabel('Upload Documents'), // Container( // height: 120, // width: double.infinity, // decoration: BoxDecoration( // color: const Color(0xFFF9F9F9), // borderRadius: BorderRadius.circular(10), // border: Border.all( // color: const Color(0xFF00A6A6), // width: 1, // ), // ), // child: const MultiFileUploadWidget(), // ), // ], // ); // } Widget formBox({required Widget child}) { return Container( height: 42, padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( color: const Color(0xFFF1F1F1), // 👈 light grey borderRadius: BorderRadius.circular(8), ), child: Center(child: child), ); } Widget fieldLabel(String text) { return Padding( padding: const EdgeInsets.only(bottom: 6), child: Text( text, style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.black, ), ), ); } } // class RaiseClaimDialog extends StatelessWidget { // const RaiseClaimDialog({super.key}); // // @override // Widget build(BuildContext context) { // return Dialog( // backgroundColor: Colors.white, // 👈 THIS // insetPadding: const EdgeInsets.all(24), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(16), // ), // child: Container( // width: MediaQuery.of(context).size.width * 0.75, // padding: const EdgeInsets.all(24), // child: Column( // mainAxisSize: MainAxisSize.min, // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // /// HEADER // Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // Text( // 'Raise Insurance Claim', // style: GoogleFonts.poppins( // fontSize: 20, // fontWeight: FontWeight.w600, // ), // ), // IconButton( // icon: const Icon(Icons.close), // onPressed: () => Navigator.pop(context), // ), // ], // ), // // const SizedBox(height: 20), // // /// FORM // Expanded( // child: SingleChildScrollView( // child: Column( // children: [ // _row([ // _dropdown('Select Policy*'), // _dropdown('Member Name'), // _input('Hospital Name'), // ]), // _row([ // _input('Hospital Address'), // _input('Hospital City'), // _input('Hospital State'), // ]), // _row([ // _input('Hospital Pincode'), // _input('Hospital Phone Number'), // _date('Admit Date'), // ]), // _row([ // _date('Discharge Date'), // _input('Claim Amount'), // _input('Message'), // ]), // // const SizedBox(height: 20), // // /// UPLOAD // _uploadBox(), // ], // ), // ), // ), // // const SizedBox(height: 20), // // /// FOOTER // Align( // alignment: Alignment.centerRight, // child: SizedBox( // width: 120, // height: 42, // child: ElevatedButton( // onPressed: () {}, // style: ElevatedButton.styleFrom( // backgroundColor: const Color(0xFFE26728), // shape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(10), // ), // ), // child: const Text( // 'Send', // style: TextStyle(fontWeight: FontWeight.w600), // ), // ), // ), // ), // ], // ), // ), // ); // } // // /// ---------- HELPERS ---------- // // Widget _row(List children) { // return Padding( // padding: const EdgeInsets.only(bottom: 14), // child: Row( // children: children // .map((e) => Expanded(child: Padding( // padding: const EdgeInsets.only(right: 12), // child: e, // ))) // .toList(), // ), // ); // } // // Widget _input(String label) { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text(label, style: _labelStyle), // const SizedBox(height: 6), // _box( // TextField( // decoration: const InputDecoration( // border: InputBorder.none, // ), // ), // ), // ], // ); // } // // Widget _dropdown(String label) { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text(label, style: _labelStyle), // const SizedBox(height: 6), // _box( // DropdownButtonHideUnderline( // child: DropdownButton( // isExpanded: true, // hint: const Text('Select'), // items: const [], // onChanged: (_) {}, // ), // ), // ), // ], // ); // } // // Widget _date(String label) { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text(label, style: _labelStyle), // const SizedBox(height: 6), // _box( // TextField( // readOnly: true, // decoration: const InputDecoration( // suffixIcon: Icon(Icons.calendar_today, size: 18), // border: InputBorder.none, // ), // ), // ), // ], // ); // } // // Widget _box(Widget child) { // return Container( // height: 42, // padding: const EdgeInsets.symmetric(horizontal: 12), // decoration: BoxDecoration( // color: const Color(0xFFF1F1F1), // borderRadius: BorderRadius.circular(8), // ), // child: Center(child: child), // ); // } // // Widget _uploadBox() { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text('Upload Documents', style: _labelStyle), // const SizedBox(height: 8), // Container( // height: 120, // width: double.infinity, // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(10), // border: Border.all( // color: const Color(0xFF00A6A6), // style: BorderStyle.solid, // ), // color: const Color(0xFFF9F9F9), // ), // child: Column( // mainAxisAlignment: MainAxisAlignment.center, // children: const [ // Icon(Icons.insert_drive_file, // size: 36, color: Color(0xFF00A6A6)), // SizedBox(height: 6), // Text( // 'Sample_file.PDF', // style: TextStyle(fontWeight: FontWeight.w500), // ), // SizedBox(height: 4), // Text( // '(Supported formats: PDF, PNG, JPG, JPEG, HEIC)', // style: TextStyle(fontSize: 11, color: Colors.grey), // ), // ], // ), // ), // ], // ); // } // } /// ---------- STYLES ---------- final _labelStyle = GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w500, );