// import 'dart:io' as html; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:toastification/toastification.dart'; import 'package:universal_html/html.dart' as html; import 'package:file_picker/file_picker.dart'; import '../../../../../core/config/env.dart'; import '../../../../../core/routing/routes.dart'; import '../../../../../core/services/api_service.dart'; import '../../../../../data/services/auth_service.dart'; import '../../../../../data/utils/toastNotification.dart'; import '../../../../../data/utils/validators.dart'; import '../../../../layouts/main_layout.dart'; import '../../../../layouts/responsive_layout.dart'; import '../../../../providers/manager_provider.dart'; import '../../../../providers/quotation_staff_proivder.dart'; import '../../../../themes/indicators/custom_loader.dart'; import '../../../../themes/indicators/customizd_file_upload.dart'; import '../../../../themes/indicators/date_field_theme.dart'; import '../../../../themes/indicators/input_field_decoration.dart'; import '../../../../themes/indicators/text_field_theme.dart'; class PolicyStaffTab extends ConsumerStatefulWidget { const PolicyStaffTab({super.key}); @override ConsumerState createState() => PolicyStaffTabState(); } class PolicyStaffTabState extends ConsumerState { int currentPage = 0; int itemsPerPage = 10; List> dataVal = []; final TextEditingController _searchController = TextEditingController(); late ApiService apiService; final _formKey = GlobalKey(); final GlobalKey>> dropDownKey = GlobalKey>>(); final GlobalKey>> dropDownKeyBroker = GlobalKey>>(); List> getBrokerData = []; List> filteredBrokerData = []; String? selectedBroker; String? selectedBrokerName; List tabHeader = [ 'name', 'email', 'mobile', 'code', 'address', 'regNo', 'insurer', 'regNum', 'idv', 'premium_amount', 'planType', 'policyInsName', 'policyPremiumAmount', 'policyIdv', 'policyNumber', 'policyPaymentMode', 'issueDate', 'startDate', 'endDate', 'tp', 'od', 'pa', 'cgst', 'sgst', 'igst', 'rto_state_code', 'rto_city_code', 'weight', 'fuel_type', 'date_of_registration', 'year_of_manufacture', 'engine_no', 'chassis_no', 'make', 'model', 'cubic_capacity', 'vehicle_type', 'premiumTOT', ]; late String isActive = "1"; PlatformFile? docUploadedFile; PlatformFile? docPDFUploadedFile; // PlatformFile? passportFile; String? selectedFileNames; String? selectedPDFFileNames; String? passportFileUrlFromApi; String? docUploadedFileUrlFromApi; String? docUploadedPDFFileUrlFromApi; String? selectedId; bool isLoading = false; bool isquotation = false; bool hasPolicyData = false; Map controllers = {}; String? _token; dynamic userId; dynamic managerId; dynamic enqQuotation; dynamic selectedEnquiryId; dynamic acceptedQuotationId; dynamic choosedPolcyId; dynamic roleId; dynamic enqBrokerName; dynamic selectedPaymentMode; List> getVehicleTypeData = []; List> filteredVechicleData = []; List> getInsurersData = []; List> filteredInsurersData = []; late Map enquiryData; late Map policyData; Map? quotationAcceptedData; Map dataDetails() { final data = { "quotation_id": acceptedQuotationId, "insured_name": controllers["policyInsName"]?.text, "issued_date": controllers["issueDate"]?.text, "start_date": controllers["startDate"]?.text, "end_date": controllers["endDate"]?.text, // "premium_amount": controllers["premium_amount"]?.text, // "premium_amount": controllers["policyPremiumAmount"]?.text, "policy_number": controllers["policyNumber"]?.text, "payment_mode": controllers["policyPaymentMode"]?.text, "broker_id": selectedBroker, "tp": controllers["tp"]?.text, "od": controllers["od"]?.text, "pa": controllers["pa"]?.text, "cgst": controllers["cgst"]?.text, "sgst": controllers["sgst"]?.text, "igst": controllers["igst"]?.text, "premium_amount": controllers["premiumTOT"]?.text, "manager_id": managerId, // "policy_pdf_file_name": "policy_doc.pdf", // "policy_payment_receipt_file_name": "receipt_doc.pdf", // "created_by": userId, }; return data; } Map dataForPolicyPDFDetails() { final data = {"quotation_id": acceptedQuotationId, "manager_id": managerId}; return data; } List> quotationData = []; List> originalData = []; List> filteredData = []; bool isLoader = false; @override void initState() { super.initState(); apiService = ApiService(); for (String field in tabHeader) { controllers[field] = TextEditingController(); } // Add listeners to text fields controllers["tp"]?.addListener(calculateAmount); controllers["od"]?.addListener(calculateAmount); controllers["pa"]?.addListener(calculateAmount); controllers["cgst"]?.addListener(calculateAmount); controllers["sgst"]?.addListener(calculateAmount); controllers["igst"]?.addListener(calculateAmount); // updateData(); _initializeToken(); // Future.microtask(() { // managerId = ref.watch(managerIdProvider); // userId = ref.watch(userIdProvider); // // getQuotationList(managerId); // }); if (kIsWeb) { Future.microtask(() => _restoreManagerId(ref)); } Future.microtask(() { managerId = ref.read(managerIdProvider); // ✅ use read userId = ref.read(userIdProvider); // ✅ use read roleId = ref.read(userRoleProvider); // ✅ use read enqBrokerName = ref.read(enqBrokerNameProvider); print('QmanagerId - $managerId'); print('QuserId - $userId'); enqQuotation = ref.read(quotationStaffIdProvider); // ✅ use read print('QenqQuotation - $enqQuotation'); controllers["cgst"]?.text = '0'; controllers["sgst"]?.text = '0'; controllers["igst"]?.text = '0'; getBroker(); if (enqQuotation != null) { _loadData(enqQuotation); } }); } Future _restoreManagerId(WidgetRef ref) async { final prefs = await SharedPreferences.getInstance(); final String? savedId = prefs.getString('enqStaffDataId'); final String? savedBrokerName = prefs.getString( 'enqBrokerName', ); // already a string if (savedBrokerName != null) { ref.read(enqBrokerNameProvider.notifier).state = savedBrokerName; } if (savedId != null) { ref.read(quotationStaffIdProvider.notifier).state = savedId; print("savedenqStaffDataId ID restored: $savedId"); _loadData(savedId); } } void calculateAmount() { print('calculateAmount 1'); setState(() { double tp = double.tryParse(controllers["tp"]?.text ?? '0') ?? 0; double od = double.tryParse(controllers["od"]?.text ?? '0') ?? 0; double pa = double.tryParse(controllers["pa"]?.text ?? '0') ?? 0; double cgst = double.tryParse(controllers["cgst"]?.text ?? '0') ?? 0; double sgst = double.tryParse(controllers["sgst"]?.text ?? '0') ?? 0; double igst = double.tryParse(controllers["igst"]?.text ?? '0') ?? 0; double total = tp + od + pa + cgst + sgst + igst; print('Val : $total'); controllers["premiumTOT"]!.text = total.toStringAsFixed(2); }); } @override void dispose() { // Dispose all TextEditingControllers for (var controller in controllers.values) { controller.dispose(); } super.dispose(); } Future _initializeToken() async { _token = await AuthService.getToken(); print("APISERTOKEN - $_token"); } Future _loadData(enqQuotation) async { getQuotationList(enqQuotation); } Future getQuotationList(enqQuotation) async { print('getClaimList called enqQuotation- $enqQuotation'); setState(() { isLoading = true; }); try { final response = await apiService.findEnqQuotePolicyView(enqQuotation); if (response['status'] == 'success') { print('quoationListData - ${response['data']}'); setState(() { enquiryData = Map.from(response['data']['enquiry']); print('enquiryData - ${enquiryData}'); updateEnquiryData(enquiryData); // quotationData = List>.from(response['data']); quotationData = List>.from( response['data']['quotations'], ); print('quotationData - ${quotationData}'); updateQuotationData(quotationData); policyData = Map.from(response['data']['policies']); print('policyData - ${policyData}'); updatePolicyData(policyData); originalData = quotationData; filteredData = List.from(originalData); // print('originalData - $getClaimPolicies'); }); } else { quotationData = []; originalData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } Future getBroker() async { print('getBroker called'); setState(() { isLoading = true; }); try { final response = await apiService.fetchMasterDropDown('Broker'); if (response['status'] == 200) { print('getBroker - ${response['data']}'); setState(() { getBrokerData = List>.from(response['data']); print('API Data - $getBrokerData'); filteredBrokerData = List.from(getBrokerData); print('originalData - $filteredBrokerData'); }); } else { getBrokerData = []; filteredBrokerData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } void updateEnquiryData(enquiryData) { setState(() { selectedEnquiryId = enquiryData['id']; print('selectedEnquiryId- $selectedEnquiryId'); controllers["regNum"]?.text = enquiryData['reg_no']; controllers["insurer"]?.text = enquiryData['insurer_name']; controllers["policyInsName"]?.text = enquiryData['name']; }); } void updateQuotationData(List> quotationData) { try { final acceptedItem = quotationData.firstWhere( (item) => item['status'] == 'Accepted', ); quotationAcceptedData = acceptedItem; print('AcceptedData YYY - $quotationAcceptedData'); if (quotationAcceptedData != null) { if (!mounted) return; print('AcceptedData YYY2'); setState(() { controllers["insurer"]?.text = quotationAcceptedData?['insurer_name']; acceptedQuotationId = quotationAcceptedData?['id']?.toString() ?? ''; controllers["idv"]?.text = quotationAcceptedData?['insured_declared_value']?.toString() ?? ''; controllers["premium_amount"]?.text = quotationAcceptedData?['premium_amount']?.toString() ?? ''; controllers["planType"]?.text = quotationAcceptedData?['insurance_plan_type']?.toString() ?? ''; controllers["policyPaymentMode"]?.text = quotationAcceptedData?['payment_mode_value']?.toString() ?? ''; selectedBroker = quotationAcceptedData?['broker_id'] ?? ''; selectedBrokerName = quotationAcceptedData?['broker_name'] ?? ''; }); } } catch (e) { quotationAcceptedData = null; print('No Accepted quotation found'); } } String fixInvalidDate(dynamic value) { if (value == null) return ''; final str = value.toString(); // Check for your invalid date patterns if (str.contains('--0001') || str == '30-11--0001' || str == '0000-00-00') { return ''; } return str; } void updatePolicyData(Map policyData) { print("updatePolicyDataupdatePolicyData - $policyData"); if (!mounted || policyData.isEmpty) return; setState(() { hasPolicyData = true; choosedPolcyId = policyData['id']?.toString() ?? ''; controllers["policyInsName"]?.text = policyData['insured_name']?.toString() ?? ''; controllers["idv"]?.text = policyData['insured_declared_value']?.toString() ?? ''; controllers["policyPremiumAmount"]?.text = policyData['premium_amount']?.toString() ?? ''; controllers["planType"]?.text = policyData['insurance_plan_type']?.toString() ?? ''; controllers["policyNumber"]?.text = policyData['policy_number']?.toString() ?? ''; controllers["policyPaymentMode"]?.text = policyData['payment_mode']?.toString() ?? ''; selectedPaymentMode = policyData['payment_mode_value']?.toString() ?? ''; controllers["issueDate"]?.text = fixInvalidDate( policyData['issued_date'], ); controllers["startDate"]?.text = fixInvalidDate(policyData['start_date']); controllers["endDate"]?.text = fixInvalidDate(policyData['end_date']); // controllers["issueDate"]?.text = // policyData['issued_date']?.toString() ?? ''; // controllers["startDate"]?.text = // policyData['start_date']?.toString() ?? ''; // controllers["endDate"]?.text = policyData['end_date']?.toString() ?? ''; controllers["tp"]?.text = policyData['tp']?.toString() ?? ''; controllers["od"]?.text = policyData['od']?.toString() ?? ''; controllers["pa"]?.text = policyData['pa']?.toString() ?? ''; controllers["cgst"]?.text = policyData['cgst']?.toString() ?? ''; controllers["sgst"]?.text = policyData['sgst']?.toString() ?? ''; controllers["igst"]?.text = policyData['igst']?.toString() ?? ''; controllers["premiumTOT"]?.text = policyData['premium_amount']?.toString() ?? ''; selectedBroker = policyData['broker_id'] ?? ''; selectedBrokerName = policyData['broker_name'] ?? ''; // RC FILE String? rcPath = policyData["policy_pdf_file_name"]; if (rcPath != null && rcPath.isNotEmpty) { selectedPDFFileNames = rcPath.split('/').last; // UI filename docUploadedPDFFileUrlFromApi = rcPath; // API download URL docPDFUploadedFile = null; // docUploadedRCFile = // rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet } else { selectedPDFFileNames = null; // no UI file shown docUploadedPDFFileUrlFromApi = null; docPDFUploadedFile = null; } // ID PROOF FILE String? idProofPath = policyData["policy_payment_receipt_file_name"]; if (idProofPath != null && idProofPath.isNotEmpty) { selectedFileNames = idProofPath.split('/').last; docUploadedFileUrlFromApi = idProofPath; // ✅ FIXED → correct variable docUploadedFile = null; // docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?; } else { selectedFileNames = null; docUploadedFileUrlFromApi = null; docUploadedFile = null; } }); } String _formatDate(String rawDate) { try { final dateTime = DateTime.parse(rawDate); return DateFormat('dd-MM-yyyy').format(dateTime); // 24-hour format } catch (e) { return rawDate; // fallback if parsing fails } } void updateUploadPDFPolicyData(Map policyData) { print('updateUploadPDFPolicyDataJJ - $policyData'); if (!mounted || policyData.isEmpty) return; setState(() { hasPolicyData = true; choosedPolcyId = policyData['id']?.toString() ?? ''; controllers["policyNumber"]?.text = policyData['policy_number']?.toString() ?? ''; controllers["policyPaymentMode"]?.text = policyData['payment_mode_value']?.toString() ?? ''; selectedPaymentMode = policyData['payment_mode_value']?.toString() ?? ''; controllers["issueDate"]?.text = _formatDate(policyData['issued_date']!.toString()) ?? ''; controllers["startDate"]?.text = _formatDate(policyData['start_date']!.toString()) ?? ''; controllers["endDate"]?.text = _formatDate(policyData['end_date']!.toString()) ?? ''; final premium = policyData['premium']; if (premium != null) { final taxes = premium['taxes'] ?? {}; controllers["tp"]?.text = premium["tp"]?.toString() ?? '0'; controllers["od"]?.text = premium["od"]?.toString() ?? '0'; controllers["pa"]?.text = premium["pa"]?.toString() ?? '0'; controllers["cgst"]?.text = taxes["cgst"]?.toString() ?? '0'; controllers["sgst"]?.text = taxes["sgst"]?.toString() ?? '0'; controllers["igst"]?.text = taxes["igst"]?.toString() ?? '0'; controllers["premiumTOT"]?.text = premium["total"]?.toString() ?? '0'; } // RC FILE String? rcPath = policyData["policy_pdf_file_name"]; if (rcPath != null && rcPath.isNotEmpty) { selectedPDFFileNames = rcPath.split('/').last; // UI filename docUploadedPDFFileUrlFromApi = rcPath; // API download URL docPDFUploadedFile = null; // docUploadedRCFile = // rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet } else { selectedPDFFileNames = null; // no UI file shown docUploadedPDFFileUrlFromApi = null; docPDFUploadedFile = null; } }); } void handleSave() { // if (!_formKey.currentState!.validate()) return; setState(() { // if (_formKey.currentState!.validate()) { calculateAmount(); dataDetails(); final dataSet = dataDetails(); print("dataSetPolicy - $dataSet"); final bool isUpdating = choosedPolcyId != null; // if (!isUpdating && selectedBrokerName == 'Nhance') { // // if (!isUpdating && enqBrokerName == 'Nhance') { // ToastHelper.showErrorToast(context, "Policy PDF is required"); // return; // } // (enqBrokerName != 'Nhance') // File validations if ( // (selectedBrokerName != 'Nhance') && (docPDFUploadedFile == null || docPDFUploadedFile?.bytes == null) && (docUploadedPDFFileUrlFromApi == null || docUploadedPDFFileUrlFromApi!.isEmpty)) { ToastHelper.showErrorToast(context, "Policy PDF is required"); return; } createUserData(dataSet); // } else { // // isDi sable = false; // } }); } void handleUploadPolicy() { setState(() { dataForPolicyPDFDetails(); final dataSet = dataForPolicyPDFDetails(); print("dataSetPolicy - $dataSet"); // File validations if ((docPDFUploadedFile == null || docPDFUploadedFile?.bytes == null) && (docUploadedPDFFileUrlFromApi == null || docUploadedPDFFileUrlFromApi!.isEmpty)) { ToastHelper.showErrorToast(context, "Policy PDF is required"); return; } createPolicyPDFData(dataSet); }); } Future attachFiles(http.MultipartRequest request) async { Future addFileOrKeepName( PlatformFile? file, String? apiFileName, String fieldName, ) async { if (file != null) { // User uploaded a new file → send as multipart if (file.bytes != null) { request.files.add( http.MultipartFile.fromBytes( fieldName, file.bytes!, filename: file.name, ), ); } else if (file.path != null) { request.files.add( await http.MultipartFile.fromPath( fieldName, file.path!, filename: file.name, ), ); } print("📎 Attached new file → $fieldName"); } else if (apiFileName != null && apiFileName.isNotEmpty) { // No new upload → tell backend to keep old file request.fields[fieldName] = apiFileName; print("🔗 Kept old file → $fieldName = $apiFileName"); } else { // Nothing at all request.fields[fieldName] = ""; } } await addFileOrKeepName( docPDFUploadedFile, docUploadedPDFFileUrlFromApi, 'policy_pdf_file_name', ); // await addFileOrKeepName( // docUploadedFile, // docUploadedFileUrlFromApi, // 'policy_payment_receipt_file_name', // ); } Future createUserData(Map userData) async { final bool isUpdating = choosedPolcyId != null; final id = choosedPolcyId; // final id = '1'; // print('UPDId- $id'); // final bool isUpdating = false; final uri = Uri.parse( isUpdating ? '${Env.apiUrl}policy/updatePolicy' : '${Env.apiUrl}policy/createPolicy', ); if (_token == null) { throw Exception('Token not found. Please log in.'); } // Use MultipartRequest (POST only) final request = http.MultipartRequest('POST', uri); request.headers['Authorization'] = 'Bearer $_token'; request.headers['app-signature'] = Env.App_Signature; // If updating, spoof the method Laravel-style if (isUpdating) { request.fields['id'] = id!; request.fields['updated_by'] = userId!.toString(); } else { request.fields['created_by'] = userId!.toString(); } print("USerDAta - $userData"); // userData.forEach((key, value) { // request.fields[key] = value.toString(); // print("✅ Encoded travel_details2: ${request.fields[key]}"); // }); await attachFiles(request); userData.forEach((key, value) { if (key != 'policy_pdf_file_name' // && // key != 'policy_payment_receipt_file_name' ) { request.fields[key] = value.toString(); print("✅ Encoded $key: ${request.fields[key]}"); } else { print('Something Missing..'); } }); // attach files // request.fields['agent_id'] = selectedId.toString(); print(" Sending request with fields: ${request.fields}"); try { final streamedResponse = await request.send(); final response = await http.Response.fromStream(streamedResponse); print("Response status: ${response.statusCode}"); print("Response body: ${response.body}"); if (response.statusCode == 200 || response.statusCode == 201) { // dispose(); print("✅ Agent submitted successfully!"); ToastHelper.showSuccessToast(context, 'Saved Policy'); print("Response: ${response.body}"); Navigator.pop(context); if (isUpdating) { ref.read(enquiryIdProvider.notifier).state = null; context.go(AppRoutes.enquiryForStaff); } else { ref.read(enquiryIdProvider.notifier).state = null; context.go(AppRoutes.enquiryForStaff); } } else if (response.statusCode == 403) { await apiService.clearLocalStorageAndRedirect(); } else { print("❌ Submission failed. Status: ${response.statusCode}"); print("Body: ${response.body}"); showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Policy Creation Failed"), content: Text( "There was a problem in creating policy. Please try again.", ), actions: [ TextButton( child: Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); } } catch (e) { print("🔥 Error submitting user: $e"); } } Future createPolicyPDFData(Map userData) async { final bool isUpdating = choosedPolcyId != null; final id = choosedPolcyId; // final id = '1'; // print('UPDId- $id'); final uri = Uri.parse('${Env.apiUrl}policy/uploadPolicyFile'); if (_token == null) { throw Exception('Token not found. Please log in.'); } // Use MultipartRequest (POST only) final request = http.MultipartRequest('POST', uri); request.headers['Authorization'] = 'Bearer $_token'; request.headers['app-signature'] = Env.App_Signature; // If updating, spoof the method Laravel-style if (isUpdating) { request.fields['id'] = id!; request.fields['updated_by'] = userId!.toString(); } else { request.fields['created_by'] = userId!.toString(); } print("USerDAta - $userData"); await attachFiles(request); userData.forEach((key, value) { if (key != 'policy_pdf_file_name') { request.fields[key] = value.toString(); print("✅ Encoded $key: ${request.fields[key]}"); } else { print('Something Missing..'); } }); print(" Sending request with fields: ${request.fields}"); showDialog( context: context, barrierDismissible: false, builder: (_) => const CustomLoader( message: 'Loading data...', loaderColor: Colors.deepPurple, useBlurBackground: true, ), ); try { final streamedResponse = await request.send(); final response = await http.Response.fromStream(streamedResponse); print("Response status: ${response.statusCode}"); print("Response body: ${response.body}"); if (response.statusCode == 200 || response.statusCode == 201) { // Close the loader before showing any message Navigator.of(context, rootNavigator: true).pop(); // dispose(); print("✅ PDF submitted successfully!"); ToastHelper.showSuccessToast(context, 'PDF Uploaded'); print("Response: ${response.body}"); final Map jsonResponse = jsonDecode(response.body); final policy = jsonResponse['data']?['file_read_data']?['value']?['policy']; if (policy != null) { final extractedData = { 'id': jsonResponse['data']?['policy_id']?.toString(), 'policy_number': policy['policy_number'], 'issued_date': policy['issue_date'], 'start_date': policy['period']?['start'], 'end_date': policy['period']?['end'], 'payment_mode': policy['payment_mode'] ?? 'online', // optional if available 'policy_pdf_file_name': jsonResponse['data']?['policy_pdf_file_name'], // ✅ include premium details here 'premium': jsonResponse['data']?['file_read_data']?['value']?['premium'], // optional if your API returns it }; print('extractedData - $extractedData'); updateUploadPDFPolicyData(extractedData); } } else if (response.statusCode == 403) { await apiService.clearLocalStorageAndRedirect(); } else { print("❌ Submission failed. Status: ${response.statusCode}"); print("Body: ${response.body}"); showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(" Upload Policy Failed"), content: Text( "There was a problem in uploading pdf. Please try again.", ), actions: [ TextButton( child: Text("OK"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); } } catch (e) { print("🔥 Error submitting user: $e"); } } @override Widget build(BuildContext context) { return Container( child: Column( children: [ // Expanded( // child: Container( // color: Colors.green, decoration: BoxDecoration( // color: Colors.orange.shade50, // color: Color(0xffEDF6F5), border: Border( top: BorderSide(color: Colors.blueGrey.shade200, width: 0.2), ), // borderRadius: BorderRadius.circular(10.0), ), width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.58, padding: EdgeInsets.all(16.0), child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [buildFormFields(context)], ), ), ), SizedBox(height: 1), // if (roleId != 'manager') ...[ // Row( // mainAxisAlignment: MainAxisAlignment.end, // children: [ // InkWell( // onTap: () { // handleSave(); // }, // child: Container( // padding: EdgeInsets.symmetric(horizontal: 45.0, vertical: 8), // // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(8.0), // color: Color(0xFF425B5B), // ), // child: Text( // // !hasPolicyData ? 'Submit' : 'Update', // 'Submit', // style: TextStyle( // color: Colors.white, // fontSize: 12, // fontWeight: FontWeight.w600, // ), // ), // ), // ), // ], // ), // ], // ), ], ), // ), ); } Widget buildDocRC(BuildContext context, bool isMobile) { return GestureDetector( onTap: () { // print("Upload $idget.id}{w"); final selectedId = selectedEnquiryId; // final path = // 'agent/downloadAgentIncentiveFile?id=$selectedId'; final path = 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc'; apiService.getPdfDownload(path, selectedId); }, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: const Color(0xFF425B5B), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( "Download RC", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w200, color: Colors.white, ), ), ?isMobile ? null : SizedBox(width: 15), // isMobile ? const Spacer() : const SizedBox(width: 15), const Icon( Icons.file_download_outlined, size: 16, color: Colors.white, ), ], ), ), ); } Widget buildDocIdProof(BuildContext context, bool isMobile) { return GestureDetector( onTap: () { print("Upload $selectedEnquiryId"); final selectedId = selectedEnquiryId; // final path = // 'agent/downloadAgentIncentiveFile?id=$selectedId'; final path = 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof'; apiService.getPdfDownload(path, selectedId); }, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: const Color(0xFF425B5B), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Download ID Proof", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w200, color: Colors.white, ), ), ?isMobile ? null : SizedBox(width: 15), // const SizedBox(width: 15), Icon(Icons.file_download_outlined, size: 16, color: Colors.white), ], ), ), ); } Widget buildDocPrevPolicy(BuildContext context, bool isMobile) { return GestureDetector( onTap: () { print("Upload $selectedEnquiryId"); final selectedId = selectedEnquiryId; // final path = // 'agent/downloadAgentIncentiveFile?id=$selectedId'; final path = 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy'; apiService.getPdfDownload(path, selectedId); }, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: const Color(0xFF425B5B), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Download Previous Policy", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w200, color: Colors.white, ), ), ?isMobile ? null : SizedBox(width: 15), // isMobile ? const Spacer() : const SizedBox(width: 15), Icon(Icons.file_download_outlined, size: 16, color: Colors.white), ], ), ), ); } Widget buildDocQuotation(BuildContext context, bool isMobile) { return GestureDetector( onTap: () { print("Upload $selectedEnquiryId"); final selectedId = acceptedQuotationId; // final path = // 'agent/downloadAgentIncentiveFile?id=$selectedId'; // final path = // 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy'; final path = 'quotation/downloadAdditionalUploadedFile?id=$acceptedQuotationId'; apiService.getPdfDownload(path, selectedId); }, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: const Color(0xFF425B5B), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Quotation Documents", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w200, color: Colors.white, ), ), ?isMobile ? null : SizedBox(width: 15), // isMobile ? const Spacer() : const SizedBox(width: 15), Icon(Icons.file_download_outlined, size: 16, color: Colors.white), ], ), ), ); } Widget buildFormFields(BuildContext context) { return Form( key: _formKey, child: Column( children: [ if (docUploadedPDFFileUrlFromApi == null || docUploadedPDFFileUrlFromApi!.isEmpty) ...[ Text('No Data Found'), ], // Show form fields when URL is NOT null AND NOT empty if (docUploadedPDFFileUrlFromApi != null && docUploadedPDFFileUrlFromApi!.isNotEmpty) ...[ Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Paymentmode(context), SizedBox(width: 20), buildBroker(context), if (selectedBrokerName != null) ...[ SizedBox(width: 20), buildUploadPolicyPdf(context), // SizedBox(width: 20), ], ], ), if (selectedBrokerName != null) ...[ SizedBox(height: 10), Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ policynumber(context), SizedBox(width: 20), policyissuedate(context), SizedBox(width: 20), policystartdate(context), SizedBox(width: 20), policyenddate(context), ], ), Row( crossAxisAlignment: CrossAxisAlignment.start, // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ buildThirdParty(context), buildOwnDamage(context), buildPersonalAccident(context), ], ), SizedBox(width: 20), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ buildCGST(context), buildSGST(context), buildIGST(context), buildPremiumTotal(context), ], ), ], ), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ InkWell( onTap: () { handleSave(); }, child: Container( padding: EdgeInsets.symmetric( horizontal: 45.0, vertical: 8, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), color: Color(0xFF425B5B), ), child: Text( // !hasPolicyData ? 'Submit' : 'Update', 'Submit', style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600, ), ), ), ), ], ), ], ], ], ), ); } Widget buildFormFields1(BuildContext context) { return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // _buildResponsiveRow( // context, // buildUploadPolicyPdf(context), // Paymentmode(context), policynumber(context), // SizedBox.shrink(), // // // policyissuedate(context), // // policystartdate(context), // // policyenddate(context), // ), // const SizedBox(height: 15), // Text("Policy TimePeriod", style: _textStrongStyle), if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), _buildResponsiveRow( context, policyissuedate(context), policystartdate(context), policyenddate(context), SizedBox.shrink(), ), // const SizedBox(height: 15), // Text("Policy TimePeriod", style: _textStrongStyle), if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), _buildResponsiveRow( context, buildThirdParty(context), buildOwnDamage(context), buildPersonalAccident(context), SizedBox.shrink(), ), if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), _buildResponsiveRow( context, buildCGST(context), buildSGST(context), buildIGST(context), SizedBox.shrink(), // buildRTOStateCode(context), // buildRTOCityCode(context), ), // if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), // _buildResponsiveRow( // context, // buildWeight(context), // buildFuelType(context), // buildDateOfRegistration(context), // buildYearOfManufacture(context), // buildEngineNo(context), // ), // // if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), // _buildResponsiveRow( // context, // buildChassisNo(context), // buildMake(context), // buildModel(context), // buildCubicCapacity(context), // buildVehicleType(context), // // SizedBox.shrink(), // ), // if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), // // // _buildResponsiveRow( // context, // Insuredname(context), // premiumamount(context), // policynumber(context), // ), // if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), // // _buildResponsiveRow( // context, // buildUploadPolicyReceipt(context), // ), // if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), // _buildResponsiveRow( // context, // buildAdditonalDocuments(context), // buildRemarks(context), // ), ], ), ); } Widget _buildResponsiveRow( BuildContext context, Widget first, Widget second, Widget third, Widget fourth, // Widget fifth, // Widget Six, ) { if (ResponsiveLayout.isMobile(context)) { // Stack vertically return Column(children: [first, const SizedBox(height: 2), second]); } else { // Place side by side return Row( children: [ Expanded(child: first), const SizedBox(width: 20), Expanded(child: second), const SizedBox(width: 20), Expanded(child: third), const SizedBox(width: 20), Expanded(child: fourth), // const SizedBox(width: 20), // Expanded(child: fifth), // const SizedBox(width: 20), // Expanded(child: Six), ], ); } } Widget registernumber(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Vehicle Number *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['regNum']!, // validator: (value) => Validators.phone(value, "phNumber"), readOnly: true, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget insurer(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Insurer*', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['insurer']!, readOnly: true, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildIdv(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('IDV *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['idv']!, readOnly: true, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } // Widget buildPremiumAmnt(BuildContext context) { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text('Premium Amount *', style: _textStyle), // SizedBox(height: 10), // ThemedFormField( // controller: controllers['premium_amount']!, // readOnly: true, // validator: (value) => // Validators.doubleNumber(value, "Premium Amount"), // txtwidth: ResponsiveLayout.isMobile(context) // ? null // : MediaQuery.of(context).size.width * 0.26, // ), // ], // ); // } Widget buildPlanType(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Plan Type *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['planType']!, readOnly: true, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget Insuredname(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Insured Name *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['policyInsName']!, validator: (value) => Validators.requiredField(value, "policyInsName"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } // // Widget premiumamount(BuildContext context) { // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text('Premium Amount ', style: _textStyle), // SizedBox(height: 10), // ThemedFormField( // controller: controllers['premium_amount']!, // // validator: (value) => // // Validators.requiredField(value, "policyPremiumAmount"), // txtwidth: ResponsiveLayout.isMobile(context) // ? null // : MediaQuery.of(context).size.width * 0.26, // ), // ], // ); // } Widget policynumber(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Policy Number ', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['policyNumber']!, borderColor: Color(0xFFE2E8F0), highlightColor: Color(0xFF50A398), // validator: (value) => Validators.requiredField(value, "policyNumber"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z 0-9]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.15, ), ], ); } Widget buildBroker(BuildContext context) { Map? selectedBrokers = filteredBrokerData.firstWhere( (item) => item['id'].toString() == selectedBroker, orElse: () => {}, ); return Row( children: [ Text('Broker *', style: _textStyle), SizedBox(width: 10), // SizedBox( // width: MediaQuery.of(context).size.width * 0.095, // child: Text( // '$selectedBrokerName', // style: GoogleFonts.inter(fontSize: 12), // ), // ), SizedBox( height: 30, width: MediaQuery.of(context).size.width * 0.1, child: DropdownSearch>( key: dropDownKeyBroker, selectedItem: selectedBrokers.isNotEmpty ? selectedBrokers : null, items: (filter, infiniteScrollProps) { return filteredBrokerData; }, itemAsString: (val) => val['name'].toString(), // what to show compareFn: (item, selectedItem) => item['id'] == selectedItem['id'], // ✅ compare by id validator: (val) { if (val == null) { return "Required"; // ✅ error message } return null; }, suffixProps: DropdownSuffixProps( // make sure the dropdown button is visible dropdownButtonProps: DropdownButtonProps( isVisible: true, padding: EdgeInsets.zero, // remove default padding constraints: const BoxConstraints( // shrink icon tap area minWidth: 12, minHeight: 12, ), iconSize: 15, // smaller icon // icon: const Icon(Icons.arrow_drop_down), ), ), dropdownBuilder: (context, selectedItem) => Align( alignment: Alignment.centerLeft, child: Text( selectedItem != null ? selectedItem['name'].toString() : "", style: GoogleFonts.poppins(fontSize: 11, color: Colors.black), overflow: TextOverflow.ellipsis, maxLines: 1, softWrap: false, ), ), decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Broker", ).copyWith( filled: true, fillColor: Color(0xffEDF6F5), // fillColor: // Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xffEDF6F5), width: 0.1, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xffEDF6F5), width: 0.1, ), ), contentPadding: EdgeInsets.symmetric( horizontal: 8, vertical: 6, ), ), ), popupProps: PopupProps.menu( fit: FlexFit.loose, constraints: BoxConstraints(maxHeight: 250), menuProps: MenuProps( backgroundColor: Colors.white, // 👈 sets dropdown background to white ), showSearchBox: true, searchFieldProps: TextFieldProps( decoration: InputDecoration( filled: true, fillColor: Colors.white, hintText: "Search Broker...", hintStyle: GoogleFonts.inter( fontSize: 12, color: Colors.black, ), enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.white, ), // 👈 Normal border ), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.white, width: 1.5, ), // 👈 Focused border ), ), ), itemBuilder: (context, item, isDisabled, isSelected) { return Container( // color: isSelected ? Colors.blue.withOpacity(0.1) : null, padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 3, ), child: Text( item['name'].toString(), style: GoogleFonts.inter(fontSize: 12, color: Colors.black), ), ); }, // constraints: BoxConstraints(), ), onChanged: (val) { if (val != null) { print("Selected Broker : ${val['name']}"); print("Id: ${val['id']}"); selectedBroker = val['id']; setState(() { selectedBrokerName = val['name']; print('selectedBrokerName - $selectedBrokerName'); }); // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } Widget Paymentmode(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.end, // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Payment Mode *', style: _textStyle), SizedBox(width: 15), SizedBox( width: MediaQuery.of(context).size.width * 0.075, child: Text( selectedPaymentMode, // controllers['policyPaymentMode']!.text, style: GoogleFonts.inter(fontSize: 12), ), ), // ThemedFormField( // controller: controllers['policyPaymentMode']!, // // borderColor: Color(0xFFE2E8F0), // borderColor: Colors.white, // highlightColor: Colors.white, // // highlightColor: Color(0xFF50A398), // errorBorderColor: Color(0xffEDF6F5), // hintText: 'Online / Cash', // // borderColor: Color(0xffEDF6F5), // readOnly: true, // validator: (value) => // Validators.requiredField(value, "policyPaymentMode"), // txtwidth: ResponsiveLayout.isMobile(context) // ? null // : MediaQuery.of(context).size.width * 0.07, // ), ], ); } Widget policyissuedate(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Issue Date', style: _textStyle), SizedBox(height: 10), ThemedDateField( hintText: "Select Date", txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, txtheight: 50, // backgroundColor: const Color(0xFFECECEC), // validator: (value) => Validators.requiredField(value, "date"), controller: controllers['issueDate']!, onDateSelected: (date) { print("Picked Date: $date"); controllers['issueDate']?.text = DateFormat( 'dd-MM-yyyy', ).format(date); // controllers['date']?.text = date as String; }, ), ], ); } Widget policystartdate(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Start Date', style: _textStyle), SizedBox(height: 10), ThemedDateField( hintText: "Select Date", txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, txtheight: 50, // backgroundColor: const Color(0xFFECECEC), // validator: (value) => Validators.requiredField(value, "date"), controller: controllers['startDate']!, onDateSelected: (date) { print("Picked Date: $date"); controllers['startDate']?.text = DateFormat( 'dd-MM-yyyy', ).format(date); // auto set end date (1 year later - 1 day if needed) final endDate = DateTime( date.year + 1, date.month, date.day, ).subtract(const Duration(days: 1)); // optional: subtract 1 day controllers['endDate']?.text = DateFormat( 'dd-MM-yyyy', ).format(endDate); print("Auto-set End Date: $endDate"); // controllers['date']?.text = date as String; }, ), ], ); } Widget policyenddate(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('End Date', style: _textStyle), SizedBox(height: 10), ThemedDateField( hintText: "Select Date", txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, txtheight: 50, // backgroundColor: const Color(0xFFECECEC), // validator: (value) => Validators.requiredField(value, "date"), validator: (value) { // if (value == null || value.isEmpty) { // return "Required"; // } final startDateControllerText = controllers['startDate']?.text; if (startDateControllerText == null || startDateControllerText.isEmpty) { return "Select start date first"; } final startDate = DateFormat( 'dd-MM-yyyy', ).parse(startDateControllerText); final endDate = DateFormat('dd-MM-yyyy').parse(value!); if (endDate.isBefore(startDate)) { return "End date cannot be before start date"; } // Minimum end date = start date + 1 year - 1 day (or just +1 year) final minEndDate = DateTime( startDate.year + 1, startDate.month, startDate.day, ).subtract(const Duration(days: 1)); if (endDate.isBefore(minEndDate)) { return "End date must be at least 1 year from start date"; } return null; // final startDateControllerText = controllers['startDate']?.text; // if (startDateControllerText == null || // startDateControllerText.isEmpty) { // return "Select start date first"; // } // // final startDate = DateFormat( // 'dd-MM-yyyy', // ).parse(startDateControllerText); // final endDate = DateFormat('dd-MM-yyyy').parse(value); // // if (endDate.isBefore(startDate)) { // return "End date cannot be before start date"; // } // // final expectedEndDate = DateTime( // startDate.year + 1, // startDate.month, // startDate.day, // ).subtract(const Duration(days: 1)); // // if (endDate != expectedEndDate) { // return "End date must be exactly 1 year from start date"; // } // // return null; // valid }, controller: controllers['endDate']!, onDateSelected: (date) { print("Picked Date: $date"); controllers['endDate']?.text = DateFormat( 'dd-MM-yyyy', ).format(date); _formKey.currentState?.validate(); // controllers['date']?.text = date as String; }, ), ], ); } Widget buildUploadPolicyPdf(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('Upload Policy PDF * ', style: _textStyle), ), // const SizedBox(height: 10), // SizedBox(width: 20), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ ThemedUploadField( hintText: selectedPDFFileNames ?? "Upload Document", allowedExtensions: ['pdf'], // backgroundColor: Colors.white, backgroundColor: Color(0xffEDF6F5), txtheight: 35, txtwidth: ResponsiveLayout.isMobile(context) ? null : (docUploadedPDFFileUrlFromApi != null) ? MediaQuery.of(context).size.width * 0.117 // ? MediaQuery.of(context).size.width * 0.135 // ? MediaQuery.of(context).size.width * 0.12 : MediaQuery.of(context).size.width * 0.14, // : MediaQuery.of(context).size.width * 0.15, // backgroundColor: Color(0xFFEDF6F5), onFileSelected: (fileName, file) async { print("Picked file: $fileName (${file.size} bytes)"); if (!fileName.toLowerCase().endsWith('.pdf')) { ToastHelper.showErrorToast( context, 'Only PDF files are allowed.', ); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Only PDF files are allowed.'), backgroundColor: Colors.red, ), ); return; // Stop here } print("Picked file: $fileName (${file.size} bytes)"); setState(() { docPDFUploadedFile = file; }); // if (selectedBrokerName == 'Nhance') { // handleUploadPolicy(); // } }, ), if (docUploadedPDFFileUrlFromApi != null) ...[ const SizedBox(width: 5), Tooltip( message: 'Download', // color: Colors.white, child: // Row( // mainAxisSize: MainAxisSize.min, // mainAxisAlignment: MainAxisAlignment.end, // children: [ InkWell( onTap: () => apiService.downloadFile( apiUrl: 'policy/downloadPolicyFile?policy_id=$choosedPolcyId&file_type=policy_pdf', apiId: choosedPolcyId, localFile: docPDFUploadedFile, fileName: selectedPDFFileNames, ), child: Container( padding: const EdgeInsets.symmetric( horizontal: 5, vertical: 8, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: Color(0xFF425B5B), // color: Colors.green.shade300, ), child: Row( children: const [ // Text( // "Download", // style: TextStyle( // fontSize: 12, // fontWeight: FontWeight.w200, // color: Colors.white, // ), // ), // SizedBox(width: 5), Icon(Icons.download, size: 13, color: Colors.white), ], ), ), ), // ], // ), ), ], ], ), ], ); } Widget buildUploadPolicyReceipt(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Upload Policy Receipt *', style: _textStyle), const SizedBox(height: 10), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ ThemedUploadField( hintText: selectedFileNames ?? "Upload Document", txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, // backgroundColor: Color(0xFFEDF6F5), onFileSelected: (fileName, file) { print("Picked file: $fileName (${file.size} bytes)"); setState(() { docUploadedFile = file; }); }, ), const SizedBox(height: 5), if (docUploadedFileUrlFromApi != null) Container( // color: Colors.white, child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.end, children: [ GestureDetector( onTap: () => apiService.downloadFile( apiUrl: 'policy/downloadPolicyFile?policy_id=$choosedPolcyId&file_type=policy_payment_receipt', apiId: choosedPolcyId, localFile: docUploadedFile, fileName: selectedFileNames, ), child: Container( padding: const EdgeInsets.all(5), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: Color(0xFF425B5B), // color: Colors.green.shade300, ), child: Row( children: const [ Text( "Download", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w200, color: Colors.white, ), ), SizedBox(width: 5), Icon(Icons.download, size: 13, color: Colors.white), ], ), ), ), ], ), ), ], ), ], ); } Widget buildResponsiveUploadField({ String? label, // 🔹 make optional required String? hintText, required void Function(String fileName, dynamic file) onFileSelected, }) { final isMobile = ResponsiveLayout.isMobile(context); final uploadWidget = ThemedUploadField( hintText: hintText ?? "Upload Documents", txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26, onFileSelected: onFileSelected, ); if (isMobile) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (label != null && label.isNotEmpty) ...[ // ✅ only render if label is given Text(label, style: _textStyle), const SizedBox(height: 8), ], uploadWidget, const SizedBox(height: 16), ], ); } else { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (label != null && label.isNotEmpty) ...[ Expanded(child: Text(label, style: _textStyle)), const SizedBox(width: 10), ], uploadWidget, ], ); } } // NEW FIELDs Widget buildThirdParty(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('Third Party', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['tp']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', // validator: (value) => Validators.requiredField(value, "Third Party"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], // onChanged: (value) => calculateAmount(), onChanged: (v) { print('pa onChanged -> $v'); // should show on every keystroke calculateAmount(); }, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildOwnDamage(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('Own Damage ', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['od']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', // validator: (value) => Validators.requiredField(value, "OwnDamage"), onChanged: (value) => calculateAmount(), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildPersonalAccident(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('Personal Accident', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['pa']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', onChanged: (value) => calculateAmount(), // validator: (value) => // Validators.requiredField(value, "PersonalAccident"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildCGST(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('CGST', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['cgst']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', validator: (value) => Validators.requiredField(value, "CGST"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildSGST(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('SGST', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['sgst']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], validator: (value) => Validators.requiredField(value, "SGST"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildIGST(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('IGST', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['igst']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', validator: (value) => Validators.requiredField(value, "IGST"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildPremiumTotal(BuildContext context) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: MediaQuery.of(context).size.width * 0.15, child: Text('Total Premium *', style: _textStyle), ), SizedBox(width: 20), ThemedFormField( controller: controllers['premiumTOT']!, // backgroundColor: Color(0xffEDF6F5), errorBorderColor: Color(0xffEDF6F5), hintText: '0', validator: (value) => Validators.requiredField(value, "premium"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.14, ), ], ); } Widget buildRTOStateCode(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('RTO State Code *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['rto_state_code']!, validator: (value) => Validators.requiredField(value, "RTO State Code"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildRTOCityCode(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('RTO City Code *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['rto_city_code']!, validator: (value) => Validators.requiredField(value, "RTO City Code"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildWeight(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Weight *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['weight']!, validator: (value) => Validators.requiredField(value, "weight"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildFuelType(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Fuel Type *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['fuel_type']!, validator: (value) => Validators.requiredField(value, "Fuel Type"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildDateOfRegistration(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Date Of Registration *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['date_of_registration']!, validator: (value) => Validators.requiredField(value, "Date Of Registration"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildYearOfManufacture(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Year Of Manufacture *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['year_of_manufacture']!, validator: (value) => Validators.requiredField(value, "Year Of Manufacture"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildEngineNo(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Engine No *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['engine_no']!, validator: (value) => Validators.requiredField(value, "Engine No"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildChassisNo(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Chassis No *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['chassis_no']!, validator: (value) => Validators.requiredField(value, "Chassis No"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildMake(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Make *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['make']!, validator: (value) => Validators.requiredField(value, "Make"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildModel(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Model *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['model']!, validator: (value) => Validators.requiredField(value, "Model"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildCubicCapacity(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Cubic Capacity *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['cubic_capacity']!, validator: (value) => Validators.requiredField(value, "Cubic Capacity"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildVehicleType(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Vehicle Type *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['vehicle_type']!, validator: (value) => Validators.requiredField(value, "Vehicle Type"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ], ); } Widget buildResponsiveField({required String label, required Widget field}) { final isMobile = ResponsiveLayout.isMobile(context); if (isMobile) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: _textStyle), const SizedBox(height: 8), field, const SizedBox(height: 16), ], ); } else { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: Text(label, style: _textStyle)), const SizedBox(width: 10), field, ], ); } } static final _textStyle = GoogleFonts.inter( fontSize: 11, color: Color(0XFF334155), fontWeight: FontWeight.w500, ); static const _textStrongStyle = TextStyle( fontSize: 12, fontWeight: FontWeight.w800, ); }