enrollment-app/lib/presentation/RaiseClaimForm.dart
2026-03-26 09:45:12 +05:30

1895 lines
68 KiB
Dart
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
import 'package:nhancepolicy/logger.dart';
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<RaiseClaimDialog> createState() => _RaiseClaimDialogState();
}
class _RaiseClaimDialogState extends State<RaiseClaimDialog> {
// const RaiseClaimDialog({super.key});
bool hasSubmitted = false;
late ApiService apiService;
bool isLoading = false;
dynamic empPrimaryId;
dynamic empClientId;
dynamic empClientBranchId;
dynamic empHrId;
final tokenService = TokenStorageService();
String? _postPreToken = '';
List<Map<String, dynamic>> policyList = [];
dynamic policyDataIsEmpty = 1;
dynamic policyHeading;
dynamic policyName;
dynamic EmployeePolicy;
List<Map<String, String>> employeeDetails = [];
dynamic argumentsData;
dynamic claimsDetails;
int? fromClaimsPage;
dynamic decodedToken;
List<Map<String, dynamic>> departmentList = [];
List<Map<String, dynamic>> 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<Map<String, dynamic>> employeePolicyList = [];
String? selectedFileNames;
// html.File? uploadedFile;
// List<html.File> uploadedFiles = [];
List<PlatformFile> uploadedFiles = [];
final fileService = FileUploadService();
bool isSubmitting = false;
dynamic getPostCardArrays = [];
List<Map<String, dynamic>> activePoliciesList = [];
int stausVal = 1;
Map<String, dynamic> getClaimPoliciesApi = {};
int? selectedPolicyTypeId;
int? selectedClientPolicyId;
Map<String, dynamic>? selectedMemberObject;
TextEditingController searchController = TextEditingController();
Map<String, dynamic> claimTypeMap = {};
List<Map<String, dynamic>> claimTypeList = [];
int? claimTypeId;
bool isClaimTypeValid = true;
// 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<String, DateTime?> selectedDates = {
"Accident Date": null,
"Date of Death": null,
};
final Map<int, List<int>> servicePolicyTypeMap = {
1: [2, 3, 4, 5],
2: [1],
3: [6],
4: [7],
};
List<Map<String, dynamic>> filteredPoliciesList = [];
// Create a unique form key for each accordion section
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
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;
bool isAccidentService = false;
bool isDeathDateValid = 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;
claimTypeId = null;
departmentList.clear();
super.dispose();
fileService.clearAll();
}
Future<void> _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<void> getClaimsPoliciesDetails() async {
logDebug('9');
setState(() {
isLoading = true;
});
try {
logDebug('10');
final response =
await apiService.getClaimPoliciesToApi(_postPreToken!, empClientId);
if (response['status'] == 'success') {
setState(() {
isLoading = false;
});
setState(() {
getClaimPoliciesApi = Map<String, dynamic>.from(response['data']);
departmentList = (getClaimPoliciesApi['ticket_type'] as List)
.map<Map<String, dynamic>>((item) => {
'id': int.parse(item['ticket_type'].toString()),
'name': item['type_name'].toString(),
})
.toList();
claimTypeMap =
Map<String, dynamic>.from(getClaimPoliciesApi['claim_type']);
logDebug('claimTypeMap $claimTypeMap');
});
} else {
setState(() {
isLoading = false;
});
// ToastHelper.showWarningToast(
// context, 'Request failed with status: ${response.statusCode}');
logDebug('Request failed with status: ${response['code']}');
}
} catch (e) {
setState(() {
// isLoading = false;
});
logDebug('Exception occurred: $e');
} finally {
setState(() {
// _isLoading = false;
});
}
}
Future<void> getPostCashDepositDetails(
empClientBranchId, empClientId, empHrId, _postPreToken) async {
logDebug('IN');
logDebug("clintBranchId -$empClientBranchId");
logDebug("clintID -$empClientId");
logDebug("hr_id -$empHrId");
logDebug("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);
logDebug('IN1');
if (response['status'] == 'success') {
isLoading = false;
setState(() {
logDebug('response');
logDebug(response['data']);
getPostCardArrays = List<Map<String, dynamic>>.from(response['data']);
logDebug('getPostCardArrays');
logDebug(getPostCardArrays);
activePoliciesList = getPostCardArrays;
});
logDebug('IN2');
} else {
isLoading = false;
logDebug('API request failed with status');
setState(() {
activePoliciesList = [];
});
logDebug('API request failed with status');
}
} catch (e) {
logDebug('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<Map<String, dynamic>>((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;
});
}
void loadClaimTypes() {
logDebug('serviceId $serviceId');
if (serviceId == null) return;
String key = serviceId.toString();
if (claimTypeMap.containsKey(key)) {
Map<String, dynamic> types = Map<String, dynamic>.from(claimTypeMap[key]);
claimTypeList = types.entries.map((entry) {
return {
'id': int.parse(entry.key),
'name': entry.value,
};
}).toList();
logDebug('claimTypeList $claimTypeList');
// // ✅ AUTO SELECT FIRST CLAIM TYPE
// if (claimTypeList.isNotEmpty) {
// claimTypeId = claimTypeList.first['id'];
// }
} else {
claimTypeList = [];
claimTypeId = null;
setState(() {});
}
}
Future<void> getCDPoliciesDetails() async {
logDebug('9');
setState(() {
isLoading = true;
});
try {
logDebug('10');
final response = await apiService.getEmployeeAndDependenceToApi(
empClientId,
selectedClientPolicyId,
empClientBranchId,
_postPreToken!);
if (response['status'] == 'success') {
final List<Map<String, dynamic>> members =
List<Map<String, dynamic>>.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;
});
logDebug('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> sendFormDataToApi() async {
setState(() {
hasSubmitted = serviceId != null ? true : false;
isServiceValid = serviceId != null;
isPolicyValid = selectedClientPolicyId != null;
isMemberValid = selectedMemberId != null;
MultiFileUploadWidget.showValidation =
serviceId != null && FileUploadService().files.isEmpty;
// MultiFileUploadWidget.showValidation = FileUploadService().files.isEmpty;
// isClaimTypeValid = claimTypeId != null;
// isSubjectValid = subjectController.text.trim().isNotEmpty;
// 🏥 GMC / Topup
final isGmc = serviceId == 1 || serviceId == 72;
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;
// isHospitalPhoneNoValid = !isGmc || (hospitalPhoneNoController.text.trim().length == 10);
String phone = hospitalPhoneNoController.text.trim();
// isHospitalPhoneNoValid = !isGmc || (RegExp(r'^\d{10}$').hasMatch(phone));
isHospitalPhoneNoValid = !isGmc || phone.isNotEmpty;
isAdmitDateValid = !isGmc || admitDate != null;
isDischargeDateValid = !isGmc || dischargeDate != null;
isClaimTypeValid = !isGmc || claimTypeId != null;
isClaimAmountValid =
!isGmc || claimAmountController.text.trim().isNotEmpty;
// ☠ Accident / Death
// final isAccident = [2, 3, 4].contains(serviceId);
//
// isAccidentService = isAccident ? true : false;
//
// isAccidentDateValid = !isAccident || accidentDate != null;
// isIntimationDateValid = !isAccident || intimationDate != null;
// 🎯 GPA / GTLI / EDLI validation
// 🎯 GPA / GTLI / EDLI dynamic validation
// if (serviceId == 2) {
// logDebug('serviceId == 2');
// isAccidentDateValid = accidentDate != null;
// isDeathDateValid = true;
// }
// else if (serviceId == 3 || serviceId == 4) {
// logDebug('serviceId == 3 || serviceId == 4');
// isDeathDateValid = deathDate != null;
// isAccidentDateValid = true;
// }
// else {
// logDebug('ELSE');
// isAccidentDateValid = true;
// isDeathDateValid = true;
// }
if (serviceId == 2) {
// GPA
isAccidentDateValid = accidentDate != null;
isDeathDateValid = true;
isIntimationDateValid = true;
} else if (serviceId == 3) {
// GTLI
isDeathDateValid = deathDate != null;
isAccidentDateValid = true;
isIntimationDateValid = true;
} else if (serviceId == 4) {
// EDLI
isDeathDateValid = deathDate != null;
isAccidentDateValid = true;
isIntimationDateValid = true;
} else {
isAccidentDateValid = true;
isDeathDateValid = true;
isIntimationDateValid = true;
}
});
// if (!isDeathDateValid) {
// ToastHelper.showErrorToast(
// context, 'Date of Death is required');
// return;
// }
//
// if (!isAccidentDateValid) {
// ToastHelper.showErrorToast(
// context, 'Accident Date is required');
// return;
// }
if (isServiceValid &&
isPolicyValid &&
isMemberValid &&
isHospitalNameValid &&
isHospitalAddressValid &&
isHospitalStateValid &&
isHospitalCityValid &&
isHospitalPincodeValid &&
isAdmitDateValid &&
isHospitalPhoneNoValid &&
isDischargeDateValid &&
isClaimAmountValid &&
isAccidentDateValid &&
isDeathDateValid &&
isIntimationDateValid) {
// ✅ Phone validation AFTER all required fields pass
// ✅ Exact 10 digit validation AFTER all required fields filled
if ((serviceId == 1 || serviceId == 72) &&
hospitalPhoneNoController.text.trim().isNotEmpty &&
!RegExp(r'^\d{10}$')
.hasMatch(hospitalPhoneNoController.text.trim())) {
ToastHelper.showErrorToast(
context,
'Hospital phone number must be exactly 10 digits',
);
return;
}
if (FileUploadService().files.isEmpty) {
ToastHelper.showErrorToast(
context,
'Please upload at least one document',
);
return;
}
} else {
ToastHelper.showErrorToast(
context,
'Please Fill Required Fields',
);
return;
}
setState(() => isSubmitting = true); // 🔥 start loader
setState(() {
isLoading = true;
});
try {
logDebug('Check One');
Map<String, dynamic> 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['claim_type'] = claimTypeId;
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 {
if (accidentDate != null) {
fields['date_of_accident'] =
DateFormat('yyyy-MM-dd').format(accidentDate!);
}
if (deathDate != null) {
fields['date_of_death'] = DateFormat('yyyy-MM-dd').format(deathDate!);
}
if (birthDate != null) {
fields['dob'] = DateFormat('yyyy-MM-dd').format(birthDate!);
}
if (intimationDate != null) {
fields['date_of_intimat'] =
DateFormat('yyyy-MM-dd').format(intimationDate!);
}
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() ?? ''));
logDebug("📁 stringFields: ${stringFields}");
request.fields.addAll(stringFields);
// get uploaded files
final uploadedFiles = FileUploadService().files;
logDebug("📁 Total uploaded files: ${uploadedFiles.length}");
logDebug(
"📂 File list (original names): ${uploadedFiles.map((f) => f.file.name).toList()}");
// Validate all labels present (optional but recommended)
for (final uf in uploadedFiles) {
logDebug(
"📝 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');
logDebug('📄 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
logDebug("Payload being sent:");
logDebug("Files: ${uploadedFiles.map((f) => f.file.name).toList()}");
logDebug("Names (JSON): $encodedNames");
final response = await request.send();
final responseBody = await response.stream.bytesToString();
final decoded = jsonDecode(responseBody);
if (decoded['status'] == true) {
resetFormOnServiceChange();
// 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);
logDebug('Form data submitted successfully');
fileService.clearAll();
} else {
setState(() {
isLoading = false;
});
Navigator.pop(context);
ToastHelper.showErrorToast(context, "Failed: ${decoded['message']}");
}
} catch (e) {
setState(() {
isLoading = false;
});
logDebug('Error submitting form data: $e');
} finally {
setState(() => isSubmitting = false); // 🔥 stop loader
}
}
Future<void> _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<void> _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<void> _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;
}
void resetFormOnServiceChange() {
hasSubmitted = false;
MultiFileUploadWidget.showValidation = false;
// Reset dropdown selections
selectedClientPolicyId = null;
selectedPolicyTypeId = null;
policyNumberId = null;
selectedMemberId = null;
selectedMemberName = null;
selectedMemberObject = null;
claimTypeId = null;
// Clear lists
employeePolicyList.clear();
policyNumberList.clear();
// Clear all text controllers
messageController.clear();
accidentDetailsController.clear();
hospitalNameController.clear();
hospitalAddressController.clear();
hospitalCityController.clear();
hospitalStateController.clear();
hospitalPinCodeController.clear();
hospitalPhoneNoController.clear();
claimAmountController.clear();
sumInsuredController.clear();
admitDateController.clear();
dischargeDateController.clear();
// Reset dates
accidentDate = null;
deathDate = null;
intimationDate = null;
birthDate = null;
admitDate = null;
dischargeDate = null;
// Reset validation flags
isPolicyValid = true;
isMemberValid = true;
isHospitalNameValid = true;
isHospitalAddressValid = true;
isHospitalCityValid = true;
isHospitalStateValid = true;
isHospitalPincodeValid = true;
isHospitalPhoneNoValid = true;
isAdmitDateValid = true;
isDischargeDateValid = true;
isClaimAmountValid = true;
isAccidentDateValid = true;
isIntimationDateValid = true;
isDeathDateValid = true;
// Clear uploaded files
fileService.clearAll();
MultiFileUploadWidget.hasFiles = false;
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
resetFormOnServiceChange();
return true;
},
child: 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: () => {
setState(() {
resetFormOnServiceChange();
}),
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(() {
resetFormOnServiceChange();
serviceId = value;
serviceName = selectedItem['name'];
policyNumberId = null;
isServiceValid = true;
});
logDebug(
'🔥 serviceId set to $serviceId');
filterPoliciesByService(value!);
loadClaimTypes();
},
departmentList,
'name',
serviceId,
required: true,
isValid: isServiceValid,
),
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,
required: true,
isValid: isPolicyValid,
),
if (serviceId == 1 || serviceId == 72)
buildDropdownField(
'Select Claim Type',
(value) {
setState(() {
claimTypeId = value;
isClaimTypeValid = true;
});
},
claimTypeList,
'name',
claimTypeId,
required: true,
isValid: isClaimTypeValid,
),
buildDropdownFieldSearch(
'Member Name',
(value) {
final member =
employeePolicyList.firstWhere(
(m) => m['id'] == value,
);
setState(() {
selectedMemberId = value;
selectedMemberObject =
member; // ✅ FULL OBJECT
selectedMemberName = member['name'];
isMemberValid = true;
logDebug(
'selectedMemberObject $selectedMemberObject');
});
},
employeePolicyList,
'name',
selectedMemberId,
required: true,
isValid: isMemberValid,
),
]),
_row([
buildTextField(
'Message', messageController),
if (serviceId == 1 || serviceId == 72) ...[
buildTextField('Hospital Name',
hospitalNameController,
required: true,
isValid: isHospitalNameValid),
buildTextField('Hospital Address',
hospitalAddressController,
required: true,
isValid: isHospitalAddressValid),
]
]),
if (serviceId == 1 || serviceId == 72)
_row([
buildTextField('Hospital City',
hospitalCityController,
required: true,
isValid: isHospitalCityValid,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r"[a-zA-Z\s]")),
]),
buildTextField('Hospital State',
hospitalStateController,
required: true,
isValid: isHospitalStateValid,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r"[a-zA-Z\s]")),
]),
buildTextField('Hospital Pincode',
hospitalPinCodeController,
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter
.digitsOnly,
LengthLimitingTextInputFormatter(6),
],
required: true,
isValid: isHospitalPincodeValid),
]),
if (serviceId == 1 || serviceId == 72)
_row([
buildTextField(
'Hospital Phone No',
hospitalPhoneNoController,
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter
.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
required: true,
isValid: !hasSubmitted ||
serviceId == null ||
(serviceId != 1 &&
serviceId != 72) ||
RegExp(r'^\d{10}$').hasMatch(
hospitalPhoneNoController.text
.trim()),
),
buildDatePickerField(
label: 'Admit Date',
selectedDate: admitDate,
allowFuture: false,
onDateSelected: (d) {
setState(() {
admitDate = d;
dischargeDate = null;
});
},
required: true,
isValid: isAdmitDateValid),
buildDatePickerField(
label: 'Discharge Date',
selectedDate: dischargeDate,
allowFuture: true,
minDate: admitDate
?.add(const Duration(days: 1)),
onDateSelected: (d) =>
setState(() => dischargeDate = d),
required: true,
isValid: isDischargeDateValid),
buildTextField('Claims Amount',
claimAmountController,
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter
.digitsOnly
],
required: true,
isValid: isClaimAmountValid),
]),
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;
});
},
required: serviceId == 2,
isValid: isAccidentDateValid),
buildDatePickerField(
label: 'Date of Death',
selectedDate: deathDate,
allowFuture: false,
onDateSelected: (d) =>
setState(() => deathDate = d),
required:
(serviceId == 3 || serviceId == 4)
? true
: false, // 🔥 GTLI & EDLI
isValid: isDeathDateValid,
),
]),
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 || serviceId == null)
? 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
if (isLoading)
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.6),
borderRadius: BorderRadius.circular(20),
),
child: Center(
child: Image.asset(
'assets/nhance-loader.gif',
height: 60,
width: 60,
),
),
),
),
],
),
),
)));
}
/// ---------- HELPERS ----------
Widget _row(List<Widget> 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 fieldLabel(String text, {bool required = false}) {
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: RichText(
text: TextSpan(
text: text,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.black,
),
children: required
? const [
TextSpan(
text: ' *',
style: TextStyle(color: Colors.red),
)
]
: [],
),
),
);
}
Widget errorText(bool isValid) {
return SizedBox(
height: 16, // fixed height for alignment
child: isValid
? null
: const Text(
"Required",
style: TextStyle(
color: Colors.red,
fontSize: 11,
),
),
);
}
Widget buildTextField(
String label,
TextEditingController controller, {
bool required = false,
bool isValid = true,
TextInputType keyboardType = TextInputType.text,
List<TextInputFormatter>? inputFormatters,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
fieldLabel(label, required: required),
formBox(
child: TextField(
controller: controller,
keyboardType: keyboardType,
inputFormatters: inputFormatters,
decoration: const InputDecoration(
isDense: true,
border: InputBorder.none,
),
),
),
errorText(isValid),
],
);
}
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<Map<String, dynamic>> itemsList,
String displayField,
int? selectedValue, {
bool required = false,
bool isValid = true,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
fieldLabel(label, required: required),
formBox(
child: DropdownButtonHideUnderline(
child: DropdownButton<int>(
isExpanded: true,
value: selectedValue,
hint: const Text('Select'),
icon: const Icon(Icons.keyboard_arrow_down),
/// ✅ This controls selected value (closed state)
selectedItemBuilder: (context) {
return itemsList.map<Widget>((item) {
return Align(
alignment: Alignment.centerLeft,
child: Text(
item[displayField] ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
softWrap: false,
),
);
}).toList();
},
/// ✅ This controls dropdown list (open state)
items: itemsList.map<DropdownMenuItem<int>>((item) {
return DropdownMenuItem<int>(
value: item['id'],
child: Text(
item[displayField] ?? '',
style: const TextStyle(fontSize: 13),
), // FULL TEXT here
);
}).toList(),
onChanged: onChanged,
),
),
),
if (required) errorText(isValid),
],
);
}
Widget buildDropdownFieldSearch(
String label,
void Function(int?) onChanged,
List<Map<String, dynamic>> itemsList,
String displayField,
int? selectedValue, {
bool required = false,
bool isValid = true,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
fieldLabel(label, required: required),
const SizedBox(height: 4),
Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: Color(0xFFF1F1F1),
borderRadius: BorderRadius.circular(8),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.08),
// blurRadius: 8,
// offset: const Offset(0, 2),
// ),
// ],
),
child: DropdownButtonHideUnderline(
child: DropdownButton2<int>(
isExpanded: true,
value: selectedValue,
hint: const Text(
'Select',
style: TextStyle(fontSize: 12),
),
iconStyleData: const IconStyleData(
icon: Icon(Icons.keyboard_arrow_down),
),
dropdownStyleData: DropdownStyleData(
maxHeight: 260,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
),
// 🔍 SEARCH SUPPORT
dropdownSearchData: DropdownSearchData(
searchController: searchController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Padding(
padding: const EdgeInsets.all(8),
child: TextField(
controller: searchController,
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
hintText: 'Search...',
hintStyle: const TextStyle(fontSize: 12),
isDense: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
searchMatchFn: (item, searchValue) {
final matchedItem = itemsList.firstWhere(
(e) => e['id'] == item.value,
orElse: () => {},
);
final text =
matchedItem[displayField]?.toString().toLowerCase() ?? '';
return text.contains(searchValue.toLowerCase());
},
),
// 🔹 CLEAR SEARCH WHEN CLOSED
onMenuStateChange: (isOpen) {
if (!isOpen) searchController.clear();
},
items: itemsList.map((item) {
return DropdownMenuItem<int>(
value: item['id'],
child: Text(
item[displayField] ?? '',
style: const TextStyle(fontSize: 12),
overflow: TextOverflow.ellipsis,
),
);
}).toList(),
onChanged: onChanged,
),
),
),
if (required) errorText(isValid),
],
);
}
Widget buildDatePickerField({
required String label,
required DateTime? selectedDate,
required bool allowFuture,
required ValueChanged<DateTime?> onDateSelected,
DateTime? minDate,
DateTime? maxDate,
bool required = false,
bool isValid = true,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
fieldLabel(label, required: required),
Container(
height: 42,
padding: const EdgeInsets.symmetric(horizontal: 12),
decoration: BoxDecoration(
color: const Color(0xFFF1F1F1),
borderRadius: BorderRadius.circular(8),
// border: required && !isValid
// ? Border.all(color: Colors.red)
// : null,
),
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,
initialEntryMode: DatePickerEntryMode.calendarOnly,
);
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),
),
// ✅ Show clear button only if date selected
if (selectedDate != null)
GestureDetector(
onTap: () {
onDateSelected(null); // 🔥 Clear date
},
child: const Icon(
Icons.close,
size: 18,
color: Colors.grey,
),
)
else
const Icon(Icons.calendar_today, size: 18),
],
),
),
),
errorText(isValid),
],
);
}
// 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),
);
}
}
// 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<Widget> 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<String>(
// 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,
);