import 'package:dropdown_search/dropdown_search.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/cupertino.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/presentation/layouts/responsive_layout.dart'; import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import 'package:toastification/toastification.dart'; import 'package:universal_html/html.dart' as html; 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/Pagination.dart'; import '../../../../data/utils/toastNotification.dart'; import '../../../../data/utils/validators.dart'; import '../../../layouts/main_layout.dart'; import '../../../providers/manager_provider.dart'; import '../../../themes/indicators/customizd_file_upload.dart'; import '../../../themes/indicators/export_btn.dart'; import '../../../themes/indicators/input_field_decoration.dart'; import '../../../themes/indicators/search_field_theme.dart'; import '../../../themes/indicators/text_field_theme.dart'; import '../../../themes/indicators/upload_doc_theme.dart' hide ThemedUploadField; class EnquiryTab extends ConsumerStatefulWidget { String? id; final Map? data; EnquiryTab({super.key, this.data, this.id}); @override ConsumerState createState() => EnquiryTabState(); } class EnquiryTabState extends ConsumerState { List> dataVal = []; final TextEditingController _searchController = TextEditingController(); late ApiService apiService; final _formKey = GlobalKey(); final GlobalKey>> dropDownKey = GlobalKey>>(); final GlobalKey>> dropDownKeyInsurer = GlobalKey>>(); final GlobalKey>> dropDownKeyAgent = GlobalKey>>(); List tabHeader = [ 'name', 'email', 'mobile', 'code', 'address', 'regNo', 'remarks', ]; late String isActive = "1"; PlatformFile? docUploadedRCFile; PlatformFile? docUploadedIDProof; PlatformFile? docUploadedPrevPolicy; String? selectedRCFile; String? selectedIdProof; String? selectedPrevPolicy; String? selectedRCFileName; String? rcFileUrlFromApi; String? idProofFileUrlFromApi; String? prevPolicyFileUrlFromApi; String? selectedId; bool isLoading = false; bool isSaving = false; String? selectedVehicleType; // int? selectedVehicleTypeId; String? selectedInsurer; String? selectedAgent; String? _token; dynamic userId; dynamic managerId; dynamic role; Map controllers = {}; List> getVehicleTypeData = []; List> filteredVechicleData = []; List> getAgentListData = []; List> filteredAgentData = []; List> getInsurersData = []; List> filteredInsurersData = []; Map dataDetails() { final data = { "agent_id": ((role == 'handler') || (role == 'manager')) ? selectedAgent : userId, "name": controllers["name"]?.text, "mobile": controllers["mobile"]?.text, "email": controllers["email"]?.text, "reg_no": controllers["regNo"]?.text, "vehicle_type_id": selectedVehicleType, "is_data_created_by_handler": role == 'handler' ? '1' : '0', "is_data_created_by_manager": role == 'manager' ? '1' : '0', // "insurer_id": selectedInsurer, // "rc_file_name": "rc_doc.pdf", // "id_proof_file_name": "id_proof.pdf", // "previous_policy_file_name": "previous_policy.pdf", "remarks": controllers["remarks"]?.text, "manager_id": managerId, "created_by": userId, }; return data; } @override void initState() { super.initState(); apiService = ApiService(); for (String field in tabHeader) { controllers[field] = TextEditingController(); } if (widget.data != null) { print("EnQ has Data"); } else { print("EnQ has Data 1"); } _initializeToken(); Future.microtask(() { managerId = ref.watch(managerIdProvider); userId = ref.watch(userIdProvider); role = ref.watch(userRoleProvider); if (managerId != null) { print('managerId - $managerId'); getAgentList(managerId); } }); getVehicleType(); getInsurers(); updateData(); } // enquiry/enquiryList?enquiry_id=1 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(); } Future getVehicleType() async { print('getClaimList called'); setState(() { isLoading = true; }); try { final response = await apiService.fetchMasterDropDown('vehicleType','dropdown'); if (response['status'] == 200) { print('getVehicleTypeData - ${response['data']}'); setState(() { getVehicleTypeData = List>.from( response['data'], ); print('API Data - $getVehicleTypeData'); filteredVechicleData = List.from(getVehicleTypeData); // print('originalData - $filteredVechicleData'); }); } else { getVehicleTypeData = []; filteredVechicleData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } 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 getAgentList(id) async { print('getAgentListData called'); setState(() { isLoading = true; }); try { final response = await apiService.fetchAgentNameDropDown(id); print('getAgentListData called response'); print('get Agent- ${response['data']}'); if (response['status'] == 'success') { print('get Agent- ${response['data']}'); setState(() { getAgentListData = List>.from(response['data']); print('API Data - $getAgentListData'); filteredAgentData = List.from(getAgentListData); print('originalAgentData - $filteredAgentData'); }); } else { getAgentListData = []; filteredAgentData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } void updateData() async { if (widget.data != null && widget.data != 'tab' && widget.id != null) { // dynamic response = await apiService.findEnqQuotePolicyView(widget.id!); // final enq = response['data']; final data = widget.data; print("updateDataEnq - $data"); if (data == null) return; setState(() { selectedId = widget.id; controllers['name']?.text = data['name'] ?? ''; controllers['email']?.text = data['email'] ?? ''; controllers['mobile']?.text = data['mobile'] ?? ''; controllers['regNo']?.text = data['reg_no'] ?? ''; controllers['remarks']?.text = data['remarks'] ?? ''; isActive = data["is_active"]; selectedVehicleType = data['vehicle_type_id'] ?? ''; selectedInsurer = data['insurer_id'] ?? ''; selectedAgent = data['agent_id'] ?? ''; String? apiDocPath = data["certificate_file_name"]; // RC FILE String? rcPath = data["rc_file_name"]; if (rcPath != null && rcPath.isNotEmpty) { selectedRCFile = rcPath.split('/').last; // UI filename selectedRCFileName = rcPath.split('/').last; rcFileUrlFromApi = rcPath; // API download URL docUploadedRCFile = null; // docUploadedRCFile = // rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet } else { selectedRCFile = null; // no UI file shown rcFileUrlFromApi = null; docUploadedRCFile = null; } // ID PROOF FILE String? idProofPath = data["id_proof_file_name"]; if (idProofPath != null && idProofPath.isNotEmpty) { selectedIdProof = idProofPath.split('/').last; idProofFileUrlFromApi = idProofPath; // ✅ FIXED → correct variable docUploadedIDProof = null; // docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?; } else { selectedIdProof = null; idProofFileUrlFromApi = null; docUploadedIDProof = null; } // PREVIOUS POLICY FILE String? prevPolicyPath = data["previous_policy_file_name"]; if (prevPolicyPath != null && prevPolicyPath.isNotEmpty) { selectedPrevPolicy = prevPolicyPath.split('/').last; prevPolicyFileUrlFromApi = prevPolicyPath; // ✅ FIXED → correct variable docUploadedPrevPolicy = null; // docUploadedPrevPolicy = prevPolicyFileUrlFromApi as PlatformFile?; } else { selectedPrevPolicy = null; prevPolicyFileUrlFromApi = null; docUploadedPrevPolicy = null; } }); } } // Future handleSave() async { // if (!_formKey.currentState!.validate()) return; // setState(() { // if (_formKey.currentState!.validate()) { // isSaving = true; // dataDetails(); // final dataSet = dataDetails(); // print("dataSetAgent - $dataSet"); // print("managerId - $managerId ,userId - $userId "); // // if ((docUploadedRCFile == null || // (docUploadedRCFile?.bytes == null && // docUploadedRCFile?.path == null)) && // (rcFileUrlFromApi == null || rcFileUrlFromApi!.isEmpty)) { // ToastHelper.showErrorToast(context, "Please upload RC Document"); // return; // } // // if ((docUploadedIDProof == null || // (docUploadedIDProof?.bytes == null && // docUploadedIDProof?.path == null)) && // (idProofFileUrlFromApi == null || idProofFileUrlFromApi!.isEmpty)) { // ToastHelper.showErrorToast(context, "Please upload ID Proof"); // return; // } // createUserData(dataSet); // } else { // // isDisable = false; // // setState(() => isSaving = false); // } // }); // } Future handleSave() async { if (!_formKey.currentState!.validate()) return; setState(() { isSaving = true; // start saving }); final dataSet = dataDetails(); try { await createUserData(dataSet); // API call // ToastHelper.showInfoToast(context, "Enquiry saved successfully"); } catch (e) { showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Error'), content: Text(e.toString()), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('OK'), ), ], ), ); } finally { setState(() => isSaving = false); // re-enable button after save } } 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( docUploadedRCFile, rcFileUrlFromApi, 'rc_file_name', ); await addFileOrKeepName( docUploadedIDProof, idProofFileUrlFromApi, 'id_proof_file_name', ); await addFileOrKeepName( docUploadedPrevPolicy, prevPolicyFileUrlFromApi, 'previous_policy_file_name', ); } Future createUserData(Map userData) async { final bool isUpdating = widget.data != null && widget.id != 'tab' && widget.id != 'null'; final id = widget.id; print('UPDId- $id'); // final bool isUpdating = false; final uri = Uri.parse( isUpdating ? '${Env.apiUrl}enquiry/updateEnquiry' : '${Env.apiUrl}enquiry/createEnquiry', ); 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 != 'rc_file_name' && key != 'id_proof_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 Enquiry'); print("Response: ${response.body}"); if (role == 'handler') { print('Im handler'); print('ROle - $role'); if (isUpdating) { context.go(AppRoutes.tabEnquiry); // context.go(AppRoutes.enquiryHandlerLst); } else { ref.read(enquiryIdProvider.notifier).state = null; context.go(AppRoutes.enquiryHandlerLst); } } else if (role == 'manager') { print('Im manager'); print('ROle - $role'); if (isUpdating) { context.go(AppRoutes.tabEnquiry); // context.go(AppRoutes.enquiryHandlerLst); } else { ref.read(enquiryIdProvider.notifier).state = null; context.go(AppRoutes.enquiryForStaff); } } else { print('Im agent'); if (isUpdating) { context.go(AppRoutes.tabEnquiry); } else { ref.read(enquiryIdProvider.notifier).state = null; context.go(AppRoutes.enquiryLst); } } setState(() => isSaving = false); } else if (response.statusCode == 403) { await apiService.clearLocalStorageAndRedirect(); } else { print("❌ Submission failed. Status: ${response.statusCode}"); print("Body: ${response.body}"); setState(() => isSaving = false); showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Enquiry Creation Failed"), content: Text( "There was a problem in creating enquiry. 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) { bool isMobile = ResponsiveLayout.isMobile(context); return SelectionArea( child: Container( // color: Colors.green, decoration: BoxDecoration( color: Color(0xffEDF6F5), borderRadius: BorderRadius.circular(10.0), ), width: MediaQuery.of(context).size.width, // height: MediaQuery.of(context).size.height * 0.8, padding: isMobile ? EdgeInsets.only(left: 14.0, right: 14.0) : EdgeInsets.all(26.0), child: Column( children: [ isMobile ? Row(children: [Expanded(child: buildFormFields(context))]) : Expanded( child: SingleChildScrollView(child: buildFormFields(context)), ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ GestureDetector( // onTap: () { // handleSave(); // }, onTap: isSaving ? null : handleSave, child: Container( padding: EdgeInsets.symmetric(horizontal: 45.0, vertical: 8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), // color: Color(0xFF425B5B), color: isSaving ? Colors.grey : Color(0xFF425B5B), ), child: Text( isSaving ? 'Saving...' : 'Save', style: TextStyle(color: Colors.white), ), ), ), ], ), SizedBox(height: 30), ], ), ) ); } Widget buildFormFields(BuildContext context) { bool isMobile = ResponsiveLayout.isMobile(context); return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ?((role == 'handler') || (role == 'manager')) ? _buildResponsiveRow( context, buildAgentName(context), SizedBox.shrink(), ) : null, ?((role == 'handler') || (role == 'manager')) ? isMobile ? SizedBox(height: 5) : SizedBox(height: 15) : null, _buildResponsiveRow(context, buildName(context), buildId(context)), isMobile ? SizedBox(height: 5) : SizedBox(height: 15), _buildResponsiveRow( context, buildVehicleType(context), buildEmail(context), ), isMobile ? SizedBox(height: 5) : SizedBox(height: 15), _buildResponsiveRow( context, buildPhNumber(context), // buildInsurer(context), buildUploadRCDocument(context), ), isMobile ? SizedBox(height: 5) : SizedBox(height: 15), _buildResponsiveRow( context, // buildUploadRCDocument(context), buildUploadIDDocument(context), buildUploadPolicyDocument(context), ), isMobile ? SizedBox(height: 5) : SizedBox(height: 15), _buildResponsiveRow( context, // buildUploadPolicyDocument(context), buildRemarks(context), SizedBox.shrink(), ), ], ), ); } Widget _buildResponsiveRow( BuildContext context, Widget first, Widget second, ) { 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: 25), Expanded(child: second), ], ); } } 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, ], ); } } Widget buildName(BuildContext context) { return buildResponsiveField( label: "Insured Name *", field: ThemedFormField( controller: controllers['name']!, validator: (value) => Validators.requiredField(value, "name"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ); } Widget buildEmail(BuildContext context) { return buildResponsiveField( label: "Email", field: ThemedFormField( controller: controllers['email']!, validator: (value) => Validators.nonReqemail(value, "email"), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')), ], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ); } Widget buildPhNumber(BuildContext context) { return buildResponsiveField( label: "Phone Number", field: ThemedFormField( controller: controllers['mobile']!, validator: (value) => Validators.nonReqphone(value, "phone"), inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]'))], txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ); } Widget buildId(BuildContext context) { return buildResponsiveField( label: "Vehicle Number *", field: ThemedFormField( controller: controllers['regNo']!, inputFormatters: [ UpperCaseTextFormatter(), // 👈 custom formatter for uppercase FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9- ]')), ], validator: (value) => Validators.requiredVechileNum(value, "regNo"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ); } Widget buildVehicleType(BuildContext context) { // Find the matching map from your list Map? selectedVehicle = filteredVechicleData.firstWhere( (item) => item['id'].toString() == selectedVehicleType, orElse: () => {}, ); return buildResponsiveField( label: "Vehicle Type *", field: Container( decoration: BoxDecoration( // color: Colors.white, borderRadius: BorderRadius.circular(10.0), ), width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, // height: 40, child: DropdownSearch>( key: dropDownKey, selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, items: (filter, infiniteScrollProps) { return filteredVechicleData; }, validator: (val) { if (val == null) { return "Required"; // ✅ error message } return null; }, itemAsString: (val) => val['vehicle_type'].toString(), compareFn: (item, selectedItem) => item['id'] == selectedItem['id'], // ✅ compare by id // decoratorProps: DropDownDecoratorProps( // decoration: // AppInputDecorations.dropdownDecoration( // label: "Select Vehicle Type", // ).copyWith( // filled: true, // fillColor: Colors.white, // 👈 makes the dropdown input white // ), // ), decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Vehicle Type", ).copyWith( filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.fromLTRB(8, 0, 0, 0), ), ), popupProps: PopupProps.menu( fit: FlexFit.loose, constraints: BoxConstraints(maxHeight: 200), menuProps: MenuProps( backgroundColor: Colors.white, // 👈 sets dropdown background to white ), showSearchBox: true, searchFieldProps: TextFieldProps( decoration: InputDecoration( filled: true, fillColor: Colors.white, hintText: "Search Vehicle 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 ), ), ), // constraints: BoxConstraints(), 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['vehicle_type'].toString(), style: GoogleFonts.inter(fontSize: 13, color: Colors.black), ), ); }, ), onChanged: (val) { if (val != null) { print("Selected vehicle_type : ${val['vehicle_type']}"); print("Id: ${val['id']}"); selectedVehicleType = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ); } Widget buildInsurer(BuildContext context) { Map? selectedInsurerd = filteredInsurersData.firstWhere( (item) => item['id'].toString() == selectedInsurer, orElse: () => {}, ); return buildResponsiveField( label: "Insurer *", field: Container( decoration: BoxDecoration( // color: Colors.white, borderRadius: BorderRadius.circular(10.0), ), width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, // height: 40, child: DropdownSearch>( key: dropDownKeyInsurer, selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null, items: (filter, infiniteScrollProps) { return filteredInsurersData; }, 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; }, decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Insurer", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white ), ), 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 Insurer...", 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 Insurer : ${val['name']}"); print("Id: ${val['id']}"); selectedInsurer = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ); } Widget buildAgentName(BuildContext context) { Map? selectedAgntName = filteredAgentData.firstWhere( (item) => item['id'].toString() == selectedAgent, orElse: () => {}, ); return buildResponsiveField( label: "Select Partner *", field: Container( decoration: BoxDecoration( // color: Colors.white, borderRadius: BorderRadius.circular(10.0), ), width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, // height: 40, child: DropdownSearch>( key: dropDownKeyAgent, selectedItem: selectedAgntName.isNotEmpty ? selectedAgntName : null, items: (filter, infiniteScrollProps) { return filteredAgentData; }, 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; }, decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Partner", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white ), ), 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 Partner...", 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 ), ), ), // constraints: BoxConstraints(), itemBuilder: (context, item, isDisabled, isSelected) { return Container( // color: isSelected ? Colors.blue.withOpacity(0.1) : null, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( item['name'].toString(), style: GoogleFonts.inter( fontSize: 13, color: Colors.black, ), ), Text( item['agent_code'].toString(), style: GoogleFonts.inter( fontSize: 13, color: Colors.grey, ), ), ], ), ); }, ), onChanged: (val) { if (val != null) { print("Selected Partner : ${val['name']}"); print("Id: ${val['id']}"); selectedAgent = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ); } // Widget buildUploadRCDocument(BuildContext context) { // return buildResponsiveUploadField( // label: "Upload RC Document", // hintText: selectedRCFile, // onFileSelected: (fileName, file) { // print("File picked: $fileName"); // setState(() { // docUploadedRCFile = file; // }); // }, // ); // } Widget buildResponsiveUploadField({ required String label, required String? hintText, required void Function(String fileName, dynamic file) onFileSelected, bool showDownload = false, VoidCallback? onRemove, VoidCallback? onDownload, }) { final isMobile = ResponsiveLayout.isMobile(context); final uploadWidget = ThemedUploadField( hintText: hintText ?? "Upload Document", txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26, onFileSelected: onFileSelected, ); final downloadRow = showDownload ? Padding( padding: const EdgeInsets.only(top: 5), child: Row( children: [ // IconButton( // onPressed: onRemove, // icon: const Icon( // Icons.remove_circle_outline_rounded, // color: Colors.redAccent, // ), // tooltip: 'Remove Upload', // ), GestureDetector( onTap: onDownload, child: Container( padding: const EdgeInsets.all(5), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: const Color(0xFF425B5B), ), 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), ], ), ), ), ], ), ) : const SizedBox.shrink(); if (isMobile) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: _textStyle), const SizedBox(height: 8), uploadWidget, Row( mainAxisAlignment: MainAxisAlignment.end, children: [downloadRow], ), const SizedBox(height: 16), ], ); } else { return Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded(child: Text(label, style: _textStyle)), const SizedBox(width: 10), uploadWidget, ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [SizedBox.shrink(), downloadRow], ), ], ); } } Widget buildUploadRCDocument(BuildContext context) { return buildResponsiveUploadField( label: "Upload RC Document ", hintText: selectedRCFile, onFileSelected: (fileName, file) { setState(() { docUploadedRCFile = file; selectedRCFileName = fileName; }); }, showDownload: docUploadedRCFile != null || rcFileUrlFromApi != null, onRemove: () { setState(() { docUploadedRCFile = null; rcFileUrlFromApi = null; selectedRCFileName = null; }); }, onDownload: () => apiService.downloadFile( // apiUrl: 'agent/downloadAgentCertificateFile?agent_id=$selectedId', apiUrl: 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc', apiId: selectedId.toString(), localFile: docUploadedRCFile, fileName: 'RC', ), ); } Widget buildUploadIDDocument(BuildContext context) { return buildResponsiveUploadField( label: "Upload ID Proof", hintText: selectedIdProof, onFileSelected: (fileName, file) { setState(() { docUploadedIDProof = file; // selectedFileNames = fileName; }); }, showDownload: docUploadedIDProof != null || idProofFileUrlFromApi != null, onRemove: () { setState(() { docUploadedIDProof = null; idProofFileUrlFromApi = null; // selectedFileNames = null; }); }, onDownload: () => apiService.downloadFile( // apiUrl: 'agent/downloadAgentCertificateFile?agent_id=$selectedId', apiUrl: 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof', apiId: selectedId.toString(), localFile: docUploadedIDProof, fileName: 'Id_Proof', ), ); } Widget buildUploadPolicyDocument(BuildContext context) { return buildResponsiveUploadField( label: "Upload Previous Policy", hintText: selectedPrevPolicy, onFileSelected: (fileName, file) { setState(() { docUploadedPrevPolicy = file; // selectedFileNames = fileName; }); }, showDownload: docUploadedPrevPolicy != null || prevPolicyFileUrlFromApi != null, onRemove: () { setState(() { docUploadedPrevPolicy = null; prevPolicyFileUrlFromApi = null; // selectedFileNames = null; }); }, onDownload: () => apiService.downloadFile( // apiUrl: 'agent/downloadAgentCertificateFile?agent_id=$selectedId', apiUrl: 'enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy', apiId: selectedId.toString(), localFile: docUploadedPrevPolicy, fileName: 'Previous_Policy', ), ); } Widget buildRemarks(BuildContext context) { return buildResponsiveField( label: "Remarks", field: ThemedFormField( maxLength: 500, controller: controllers['remarks']!, keyboardType: TextInputType.multiline, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, ), ); } static const _textStyle = TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ); }