import 'dart:convert'; import 'package:dropdown_search/dropdown_search.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:nhance_partner/data/utils/toastNotification.dart'; import 'package:shared_preferences/shared_preferences.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/validators.dart'; import '../../../../layouts/responsive_layout.dart'; import '../../../../providers/manager_provider.dart'; import '../../../../providers/quotation_staff_proivder.dart'; import '../../../../themes/indicators/customizd_file_upload.dart'; import '../../../../themes/indicators/input_field_decoration.dart'; import '../../../../themes/indicators/text_field_theme.dart'; class CreateProposalForm extends ConsumerStatefulWidget { final dynamic userId; final dynamic managerId; final dynamic selectedEnquiryId; final dynamic selectedInsurdId; final dynamic selectedQuotationFrmListdata; final dynamic selectedQuotationFrmListId; final void Function(String value) onSubmit; const CreateProposalForm({ super.key, required this.userId, required this.managerId, required this.selectedEnquiryId, required this.selectedInsurdId, this.selectedQuotationFrmListdata, this.selectedQuotationFrmListId, required this.onSubmit, }); @override ConsumerState createState() => CreateProposalFormState(); // State createState() => _CreateProposalFormState(); } class CreateProposalFormState extends ConsumerState { late ApiService apiService; String? _token; String? selectedFileNames; List> getInsurersData = []; List> filteredInsurersData = []; String? selectedInsurer; bool isLoading = false; bool _autoValidate = false; late TextEditingController controller; Map controllers = {}; final _formKey = GlobalKey(); String? docUploadedFileUrlFromApi; String? selectedId; PlatformFile? docUploadedFile; final GlobalKey>> dropDownKey = GlobalKey>>(); final GlobalKey>> dropDownKeyBroker = GlobalKey>>(); final GlobalKey>> dropDownKeyInsurerEnqAsgn = GlobalKey>>(); final GlobalKey>> dropDownKeyInsurer = GlobalKey>>(); final GlobalKey>> dropDownSelectPaymentModeKey = GlobalKey>>(); List tabHeader = ['idv', 'premium_Amount', 'insurer']; List> getBrokerData = []; List> filteredBrokerData = []; String? selectedBroker; List> getPaymentModeData = []; List> filteredPaymentModeData = []; List> getInsuranceTypeData = []; List> filteredInsuranceData = []; String? selectedInsPlanType; String? selectedEndorsement; String? selectedPaymentMode; Map dataDetails() { final data = { "enquiry_id": widget.selectedEnquiryId, "insured_declared_value": controllers["idv"]?.text, // "insurer_id": widget.selectedInsurdId, "insurer_id": selectedInsurer, "premium_amount": controllers["premium_Amount"]?.text, "insurance_plan_type_id": selectedInsPlanType, "payment_mode_id": selectedPaymentMode, "broker_id": selectedBroker, // "additional_uploaded_file_name": "extra_doc.pdf", // "created_by": widget.userId, "manager_id": widget.managerId, }; return data; } @override void initState() { super.initState(); apiService = ApiService(); for (String field in tabHeader) { controllers[field] = TextEditingController(); } // 🔹 Init logic here (API calls, token fetch, etc.) _initializeToken(); getInsuranceType(); getPaymentMode(); getInsurers(); updateData(); getBroker(); } Future _initializeToken() async { _token = await AuthService.getToken(); print("APISERTOKEN - $_token"); } @override void dispose() { // Dispose all TextEditingControllers for (var controller in controllers.values) { controller.dispose(); } super.dispose(); } void reset() { print('RESET'); _formKey.currentState?.reset(); // Clear all TextEditingControllers for (var controller in controllers.values) { controller.clear(); } dropDownKey.currentState?.changeSelectedItem(null); dropDownKeyInsurer.currentState?.changeSelectedItem(null); // Reset dropdowns / selections selectedInsurer = null; selectedInsPlanType = null; selectedEndorsement = null; // Reset file selection selectedFileNames = null; docUploadedFile = null; docUploadedFileUrlFromApi = null; // Reset selected ID selectedId = null; // Trigger UI update setState(() {}); } 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 updateData() { selectedInsurer = widget.selectedInsurdId; print('QuickselectedInsurer - $selectedInsurer'); print('QuickselectedEnquiryId - ${widget.selectedEnquiryId}'); if (widget.selectedQuotationFrmListId != null && widget.selectedQuotationFrmListdata!.isNotEmpty) { print('checkData -- ${widget.selectedQuotationFrmListdata}'); selectedId = widget.selectedQuotationFrmListId!; // Pre-fill controllers controllers["idv"]?.text = widget.selectedQuotationFrmListdata!['insured_declared_value'] ?.toString() ?? ''; controllers["premium_Amount"]?.text = widget.selectedQuotationFrmListdata!['premium_amount']?.toString() ?? ''; selectedInsPlanType = widget .selectedQuotationFrmListdata!['insurance_plan_type_id'] ?.toString(); selectedBroker = widget.selectedQuotationFrmListdata!['broker_id'] ?.toString(); selectedPaymentMode = widget .selectedQuotationFrmListdata!['payment_mode_id'] ?.toString(); // controllers["insurer"]?.text = 'LIC'; selectedInsurer = widget.selectedInsurdId; // widget.selectedQuotationFrmListdata!['insurer_id']?.toString() ?? ''; String? apiDocPath = widget.selectedQuotationFrmListdata!["policy_pdf_file_name"]; if (apiDocPath != null && apiDocPath.isNotEmpty) { print('apiDocPath - $apiDocPath'); selectedFileNames = apiDocPath.split('/').last; print('selectedFileNames - $selectedFileNames'); docUploadedFileUrlFromApi = apiDocPath; print('passportFileUrlFromApi - $docUploadedFileUrlFromApi'); docUploadedFile = null; } else { selectedFileNames = null; docUploadedFile = null; docUploadedFileUrlFromApi = null; } } } Future getInsurers() async { print('Insurers called'); setState(() { isLoading = true; }); try { final response = await apiService.fetchMasterDropDown('Insurers'); if (response['status'] == 200) { print('getInsurers - ${response['data']}'); setState(() { getInsurersData = List>.from(response['data']); print('API Data - $getInsurersData'); filteredInsurersData = List.from(getInsurersData); print('originalData - $filteredInsurersData'); }); } else { getInsurersData = []; filteredInsurersData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } Future getInsuranceType() async { print('getClaimList called'); setState(() { isLoading = true; }); try { final response = await apiService.fetchMasterDropDown('InsuranceType'); if (response['status'] == 200) { print('getInsuranceTypeData - ${response['data']}'); setState(() { getInsuranceTypeData = List>.from( response['data'], ); print('API Data - $getInsuranceTypeData'); filteredInsuranceData = List.from(getInsuranceTypeData); print('originalData - $filteredInsuranceData'); }); } else { getInsuranceTypeData = []; filteredInsuranceData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } Future getPaymentMode() async { print('getPaymentMode called'); setState(() { isLoading = true; }); try { final response = await apiService.fetchMasterDropDown('PaymentMode'); if (response['status'] == 200) { print('getPaymentModeData - ${response['data']}'); setState(() { getPaymentModeData = List>.from( response['data'], ); print('API Data - $getPaymentModeData'); filteredPaymentModeData = List.from(getPaymentModeData); print('originalData - $filteredPaymentModeData'); }); } else { getPaymentModeData = []; filteredPaymentModeData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } void handleDone() { if (!_formKey.currentState!.validate()) return; // setState(() { // _autoValidate = true; // enable autovalidation after first save attempt // }); setState(() { if (_formKey.currentState!.validate()) { dataDetails(); final dataSet = dataDetails(); print("dataSetAgent - $dataSet"); // print("managerId - $managerId ,userId - $userId "); createUserData(dataSet); } else { // isDi sable = false; } }); } Future createUserData(Map userData) async { // final bool isUpdating = widget.selectedQuotationFrmListId != null; // final id = widget.selectedQuotationFrmListId!; print("userDatauserData1 - $userData"); final bool isUpdating = widget.selectedQuotationFrmListId != null; final id = widget.selectedQuotationFrmListId; // keep nullable print('id - $id'); final uri = Uri.parse( // isUpdating // ? '${Env.apiUrl}quotation/updateQuotation' // : '${Env.apiUrl}quotation/createQuotation', '${Env.apiUrl}quotation/proceedQuotation', ); 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) { print('Updatrinf'); // request.fields['_method'] = 'PUT'; request.fields['id'] = id!; request.fields['updated_by'] = widget.userId!.toString(); request.fields['created_by'] = widget.userId!.toString(); } else { print('Not Updatrinf'); request.fields['created_by'] = widget.userId!.toString(); } print("USerDAta - $userData"); // userData.forEach((key, value) { // request.fields[key] = value.toString(); // print("✅ Encoded travel_details2: ${request.fields[key]}"); // }); userData.forEach((key, value) { // if (key != 'certificate_file_name') { request.fields[key] = value.toString(); print("✅ Encoded $key: ${request.fields[key]}"); // } }); if (docUploadedFile != null) { try { if (docUploadedFile!.bytes != null) { final multipartFile = http.MultipartFile.fromBytes( 'policy_pdf_file_name', docUploadedFile!.bytes!, filename: docUploadedFile!.name, ); request.files.add(multipartFile); } else if (docUploadedFile!.path != null) { final multipartFile = await http.MultipartFile.fromPath( 'policy_pdf_file_name', docUploadedFile!.path!, filename: docUploadedFile!.name, ); request.files.add(multipartFile); } print("📎 File attached: ${docUploadedFile!.name}"); } catch (e) { print("❌ Failed to attach file: $e"); } } 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!"); print("Response: ${response.body}"); widget.onSubmit('Success'); // ToastHelper.showErrorToast(context, 'Proposal Created'); reset(); Navigator.of(context).pop(); } else if (response.statusCode == 403) { await apiService.clearLocalStorageAndRedirect(); } else { final responseBody = jsonDecode(response.body); dynamic msg = responseBody['data']; print("❌ Submission failed. Status: ${response.statusCode}"); print("Body: ${response.body}"); ToastHelper.showErrorToast(context, 'Proposal Creation Failed'); } } catch (e) { print("🔥 Error submitting user: $e"); } } @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, children: [ // Header row // Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, // children: [ // Text( // widget.selectedQuotationFrmListId != null // ? 'Update Proposal' // : 'Create Proposal', // style: GoogleFonts.inter( // color: const Color(0xFF374141), // fontSize: 14, // fontWeight: FontWeight.w600, // ), // ), // ], // ), // // const SizedBox(height: 8), // 🔹 Switch content dynamically Container( width: MediaQuery.of(context).size.width, // height: MediaQuery.of(context).size.height * 0.525, child: buildFormFields(context), ), ], ); } Widget buildFormFields(BuildContext context) { return Form( key: _formKey, child: Column( children: [ Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ // buildIdv(context), buildInsurer(context), Spacer(), buildInsurancePlanType(context), Spacer(), buildPremiumAmnt(context), Spacer(), // buildDocuments(context), // if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), // _buildResponsiveRow( // context, // buildAdditonalDocuments(context), // buildRemarks(context), // ), ], ), // SizedBox(height: 10), // Row( // crossAxisAlignment: CrossAxisAlignment.end, // // children: [ // buildPaymentMode(context), // Spacer(), // // buildInsurer(context), // buildBroker(context), // Spacer(), // // buildDocuments(context), // GestureDetector( // onTap: () { // handleDone(); // // widget.onSubmit(controller.text.trim()); // // Navigator.of(context).pop(); // }, // child: Container( // padding: const EdgeInsets.symmetric( // horizontal: 25.0, // vertical: 10, // ), // decoration: BoxDecoration( // borderRadius: BorderRadius.circular(8.0), // color: const Color(0xFF2E7D6E), // ), // child: Text( // 'Save', // style: GoogleFonts.poppins( // color: Colors.white, // fontSize: 12, // fontWeight: FontWeight.w500, // ), // ), // ), // ), // Spacer(), // ], // ), SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ GestureDetector( onTap: () { handleDone(); // widget.onSubmit(controller.text.trim()); // Navigator.of(context).pop(); }, child: Container( padding: const EdgeInsets.symmetric( horizontal: 25.0, vertical: 10, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), color: const Color(0xFF2E7D6E), ), child: Text( 'Save', style: GoogleFonts.poppins( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, ), ), ), ), ], ), ], ), ); } // ------------------------- Claims Part ----------------------------------- Widget buildIdv(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('IDV *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['idv']!, inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), ], validator: (value) => Validators.doubleNumber(value, "IDV"), borderColor: Color(0xFFE2E8F0), highlightColor: Color(0xFF50A398), // validator: (value) => Validators.number(value, "IDV"), // backgroundColor: Color(0xFFEDF6F5), // readOnly: true, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.12, txtheight: 40, ), ], ); } Widget buildPremiumAmnt(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Premium Amount *', style: _textStyle), SizedBox(height: 10), ThemedFormField( controller: controllers['premium_Amount']!, borderColor: Color(0xFFE2E8F0), highlightColor: Color(0xFF50A398), // backgroundColor: Color(0xFFEDF6F5), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), ], validator: (value) => Validators.doubleNumber(value, "PremiumAmount"), // validator: (value) => Validators.number(value, "PremiumAmount "), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.12, txtheight: 40, ), ], ); } Widget buildInsurancePlanType(context) { Map? selectedVehicle = filteredInsuranceData.firstWhere( (item) => item['id'].toString() == selectedInsPlanType, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Plan Type *", style: _textStyle), SizedBox(height: 10), Container( color: Colors.white, width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.12, // height: 35, child: DropdownSearch>( key: dropDownKey, selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, // items: (filter, infiniteScrollProps) { // return filteredInsuranceData; // }, items: (filter, infiniteScrollProps) async { if (filter.isEmpty) { return filteredInsuranceData; } return filteredInsuranceData.where((item) { return item['name'].toString().toLowerCase().contains( filter.toLowerCase(), ); }).toList(); }, itemAsString: (val) => val['insurance_plan_type'].toString(), compareFn: (item, selectedItem) => item['id'] == selectedItem['id'], // ✅ compare by id validator: (val) { if (val == null) { return "Required"; // ✅ error message } return null; }, decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Plan Type", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), 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( autofocus: true, decoration: InputDecoration( contentPadding: EdgeInsets.all(1), filled: true, fillColor: Colors.white, hintText: "Search Plan Type ...", 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['insurance_plan_type'].toString(), style: GoogleFonts.inter(fontSize: 11, color: Colors.black), ), ); }, // searchFieldProps: TextFieldProps( // decoration: InputDecoration( // filled: true, // fillColor: Colors.white, // hintText: "Search Plan Type...", // enabledBorder: OutlineInputBorder( // borderSide: BorderSide( // color: Colors.white, // ), // 👈 Normal border // ), // focusedBorder: OutlineInputBorder( // borderSide: BorderSide( // color: Colors.white, // width: 1.5, // ), // 👈 Focused border // ), // ), // ), // constraints: BoxConstraints(), ), onChanged: (val) { if (val != null) { print("Selected ClaimsType : ${val['insurance_plan_type']}"); print("Id: ${val['id']}"); selectedInsPlanType = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } Widget buildInsurer(BuildContext context) { Map? selectedInsurerd = filteredInsurersData.firstWhere( (item) => item['id'].toString() == widget.selectedInsurdId, // (item) => item['id'].toString() == selectedInsurer, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Insurer *', style: _textStyle), SizedBox(height: 5), Container( // height: 30, width: MediaQuery.of(context).size.width * 0.12, child: DropdownSearch>( key: dropDownKeyInsurerEnqAsgn, selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null, // items: (filter, infiniteScrollProps) { // return filteredInsurersData; // }, // 👇 Enable async filtering based on user input items: (filter, infiniteScrollProps) async { if (filter.isEmpty) { return filteredInsurersData; } return filteredInsurersData.where((item) { return item['short_name'].toString().toLowerCase().contains( filter.toLowerCase(), ); }).toList(); }, itemAsString: (val) => val['short_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['short_name'].toString() : "", style: GoogleFonts.poppins(fontSize: 11, color: Colors.black), overflow: TextOverflow.ellipsis, maxLines: 1, softWrap: false, ), ), decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Insurer", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), contentPadding: EdgeInsets.symmetric( horizontal: 8, vertical: 6, ), ), ), popupProps: PopupProps.menu( fit: FlexFit.loose, searchDelay: Duration(milliseconds: 200), constraints: BoxConstraints(maxHeight: 250), menuProps: MenuProps( backgroundColor: Colors.white, // 👈 sets dropdown background to white ), showSearchBox: true, searchFieldProps: TextFieldProps( autofocus: true, decoration: InputDecoration( contentPadding: EdgeInsets.all(1), filled: true, fillColor: Colors.white, hintText: "Search Insurer...", hintStyle: GoogleFonts.inter( fontSize: 11, 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['short_name'].toString(), style: GoogleFonts.inter(fontSize: 12, color: Colors.black), ), ); }, // constraints: BoxConstraints(), ), onChanged: (val) { if (val != null) { print("Selected Insurer : ${val['short_name']}"); print("Id: ${val['id']}"); selectedInsurer = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } Widget buildPaymentMode(context) { Map? selectedVehicle = filteredPaymentModeData.firstWhere( (item) => item['id'].toString() == selectedPaymentMode, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Payment Mode", style: _textStyle), SizedBox(height: 10), Container( color: Colors.white, width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.12, // height: 35, child: DropdownSearch>( key: dropDownSelectPaymentModeKey, selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, // items: (filter, infiniteScrollProps) { // return filteredInsuranceData; // }, items: (filter, infiniteScrollProps) async { if (filter.isEmpty) { return filteredPaymentModeData; } return filteredPaymentModeData.where((item) { return item['name'].toString().toLowerCase().contains( filter.toLowerCase(), ); }).toList(); }, itemAsString: (val) => val['value'].toString(), compareFn: (item, selectedItem) => item['id'] == selectedItem['id'], // ✅ compare by id validator: (val) { if (val == null) { return "Required"; // ✅ error message } return null; }, decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Payment Mode", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), 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( autofocus: true, decoration: InputDecoration( contentPadding: EdgeInsets.all(1), filled: true, fillColor: Colors.white, hintText: "Search Payment Mode ...", 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['value'].toString(), style: GoogleFonts.inter(fontSize: 12, color: Colors.black), ), ); }, ), onChanged: (val) { if (val != null) { print("Selected value : ${val['value']}"); print("Id: ${val['id']}"); selectedPaymentMode = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } Widget buildBroker(context) { Map? selectedBrokers = filteredBrokerData.firstWhere( (item) => item['id'].toString() == selectedBroker, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Broker", style: _textStyle), SizedBox(height: 10), Container( color: Colors.white, width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.12, // height: 35, child: DropdownSearch>( key: dropDownKeyBroker, selectedItem: selectedBrokers.isNotEmpty ? selectedBrokers : null, // items: (filter, infiniteScrollProps) { // return filteredInsuranceData; // }, items: (filter, infiniteScrollProps) async { if (filter.isEmpty) { return filteredBrokerData; } return filteredBrokerData.where((item) { return item['name'].toString().toLowerCase().contains( filter.toLowerCase(), ); }).toList(); }, itemAsString: (val) => val['name'].toString(), compareFn: (item, selectedItem) => item['id'] == selectedItem['id'], // ✅ compare by id validator: (val) { if (val == null) { return "Required"; // ✅ error message } return null; }, decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Broker", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0xFFE2E8F0), width: 0.5, ), ), 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( autofocus: true, decoration: InputDecoration( contentPadding: EdgeInsets.all(1), 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), ), ); }, ), onChanged: (val) { if (val != null) { print("Selected ClaimsType : ${val['id']}"); print("Id: ${val['id']}"); selectedBroker = val['id']; } }, ), ), ], ); } Widget buildDocuments(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Upload Policy PDF', style: _textStyle), const SizedBox(height: 10), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ ThemedUploadField( hintText: selectedFileNames ?? "Upload Document", // txtheight: 40, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.18, borderColor: Color(0xFFE2E8F0), // highlightColor: Color(0xFF50A398), // 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(() { docUploadedFile = file; }); // if (selectedBrokerName == 'Nhance') { // handleUploadPolicy(); // } }, // 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( // children: [ // GestureDetector( // onTap: () => apiService.downloadFile( // // apiUrl: // // 'quotation/downloadAdditionalUploadedFile?id=$selectedId', // apiUrl: // 'policy/downloadPolicyFile?policy_id=$selectedId&file_type=policy_pdf', // apiId: selectedId, // 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 [ // Icon(Icons.download, size: 13, color: Colors.white), // ], // ), // ), // ), // ], // ), // ), ], ), ], ); } // ------------------- STyle --------------------------------- static final TextStyle _textStyle = TextStyle( fontSize: 11, color: Color(0XFF334155), fontWeight: FontWeight.w500, ); }