import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.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/responsive_layout.dart'; import '../../../providers/manager_provider.dart'; import '../../../providers/userRoleProvider.dart'; import '../../../themes/indicators/input_field_decoration.dart'; import '../../../themes/indicators/text_field_theme.dart'; import '../../../themes/indicators/text_field_theme_inline_editor.dart' hide UpperCaseTextFormatter; import '../../../themes/indicators/date_field_theme.dart'; class SubRowWidget extends ConsumerStatefulWidget { final String selectId; final int rowId; final Function(String) onSave; final VoidCallback onClose; // dropdown values & controllers final Map controllers; final List> filteredStaffDataEnqAsgn; final List> filteredAgentData; final String? selectedStaff; final String? selectedAgent; final String? selectedInsurer; final String? selectedBroker; // final String? selectedVehicleType; final Function(String?)? onStaffChanged; final Function(String?)? onAgentChanged; final Function(String?)? onInsurerChanged; final Function(String?)? onBrokerChanged; // final Function(String?)? onVehicleTypeChanged; const SubRowWidget({ super.key, required this.selectId, required this.rowId, required this.onSave, required this.onClose, required this.controllers, required this.filteredStaffDataEnqAsgn, required this.filteredAgentData, required this.selectedStaff, required this.selectedAgent, required this.selectedInsurer, required this.selectedBroker, // required this.selectedVehicleType, this.onStaffChanged, this.onAgentChanged, this.onInsurerChanged, this.onBrokerChanged, // this.onVehicleTypeChanged, }); @override ConsumerState createState() => _SubRowWidgetState(); } class _SubRowWidgetState extends ConsumerState { late ApiService apiService; dynamic userId; dynamic idPrimary; dynamic managerId; dynamic dashboardKey; dynamic quickQuotationKey; dynamic SelectedStatus; dynamic SelectedStaffId; String? selectedFileNames; String? lastPickedFile; dynamic handlerId; String? _token; final _formKey = GlobalKey(); Map fieldErrors = {}; List> getStaffData = []; List> originalData = []; List> filteredData = []; bool isLoading = false; bool isLoadingInsurers = false; bool isLoadingInsuranceType = false; bool isLoadingBroker = false; bool isLoadingPaymentMode = false; bool isLoadingStaffEnqAssign = false; bool isLoadingStaffList = false; bool isLoadingVehicleType = false; bool isLoadingAgentList = false; dynamic roleId; bool _showFilterRow = false; Map rowExpanded = {}; Map controllers = {}; String formRebuildKey = UniqueKey().toString(); Map isEditingRow = {}; Map> rowControllers = {}; //---------------------- Enquiry TAB Initializations Starts -------------------------------- // List> getVehicleTypeData = []; List> filteredVechicleData = []; // List> filteredVehicleData = []; List> getAgentListData = []; List> filteredAgentData = []; List> getInsurersData = []; List> filteredInsurersData = []; List> getPaymentModeData = []; List> filteredPaymentModeData = []; List> getInsuranceTypeData = []; List> filteredInsuranceData = []; final GlobalKey>> dropDownKey = GlobalKey>>(); final GlobalKey>> dropDownKeyInsurer = GlobalKey>>(); final GlobalKey>> dropDownKeyAgent = GlobalKey>>(); final GlobalKey>> dropDownSelectPaymentModeKey = GlobalKey>>(); //---------------------- Assign Staff starts -------------------------------- // final GlobalKey>> dropDownKeyInsurerEnqAsgn = GlobalKey>>(); // final GlobalKey>> // dropDownKeyVehicleTypeEnqAsgn = // GlobalKey>>(); final GlobalKey>> dropDownKeyBroker = GlobalKey>>(); final GlobalKey>> dropDownSelectStaffKey = GlobalKey>>(); List> getStaffDetailsDataEnqAsgn = []; List> filteredStaffDataEnqAsgn = []; List> getBrokerData = []; List> filteredBrokerData = []; // String? selectedBroker; int selectedSeconds = 30; bool isActionable = false; //---------------------- Assign Staff Ends -------------------------------- // //---------------------- Enquiry TAB Initializations Ends -------------------------------- // @override void initState() { super.initState(); apiService = ApiService(); // // ▼ TAKE EDIT VALUES FROM PARENT // selectedAgent = widget.selectedAgent; // selectedStaff = widget.selectedStaff; // selectedInsurer = widget.selectedInsurer; // selectedBroker = widget.selectedBroker; // ▼ USE PARENT CONTROLLERS DIRECTLY (do not recreate) controllers = widget.controllers.map( (key, value) => MapEntry(key, value as TextEditingController), ); _initializeToken(); loadPreferences(); Future.microtask(() async { // final id = ref.read(managerIdProvider); roleId = ref.read(userRoleProvider); userId = ref.read(userIdProvider); managerId = ref.read(managerIdProvider); final prefs = await SharedPreferences.getInstance(); dashboardKey = prefs.getString('dashboardKeyProvider'); quickQuotationKey = prefs.getString('QuoteKeyProvider'); final dashboardStatus = prefs.getString('dashboardStatusProvider'); final dashboardStaffId = prefs.getString('dashboardStaffIdProvider'); print('handlerIdENQ - $handlerId'); print("C72 => r : $roleId | uId: $userId !mID : $managerId "); print('quickQuotationKey'); if (managerId != null) { print('managerId - $managerId'); getAgentList(managerId); } final userID = ref.watch(userIdProvider); print("managerId - $managerId"); if (userID != null) { print('hansles'); getStaffDetailsForEnquiryAssignment(userID); } }); getInsurers(); getBroker(); // getVehicleType(); } Future loadPreferences() async { final prefs = await SharedPreferences.getInstance(); setState(() { isActionable = prefs.getBool('isActionable') ?? false; selectedSeconds = prefs.getInt('selectedSeconds') ?? 30; _showFilterRow = true; }); } Future resetPreferences() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('isActionable'); await prefs.remove('selectedSeconds'); setState(() { // isActionable = false; // default selectedSeconds = 30; // default }); print("Storage cleared & reset completed"); } Future _initializeToken() async { _token = await AuthService.getToken(); print("APISERTOKEN - $_token"); } Future getAgentList(id) async { print('getAgentListData called'); setState(() { isLoadingAgentList = 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(() { isLoadingAgentList = false; }); } } Future getInsurers() async { print('Insurers called'); setState(() { isLoadingInsurers = 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(() { isLoadingInsurers = false; }); } } // Future getVehicleType() async { // print('EIS 1getVT-called'); // setState(() { // isLoadingVehicleType = true; // }); // // try { // final response = await apiService.fetchMasterDropDown('vehicleType'); // // if (response['status'] == 200) { // print('EIS 2getVT-Data - ${response['data']}'); // setState(() { // getVehicleTypeData = List>.from( // response['data'], // ).where((item) => item['is_active'] == 1).toList(); // // print('EIL 3getVT-B4filterData : $getVehicleTypeData'); // // filteredVehicleData = List.from(getVehicleTypeData); // // print('EIL 3getVT-AftfilterData : $filteredVehicleData'); // }); // } else { // getVehicleTypeData = []; // filteredVehicleData = []; // } // } catch (e) { // print('EIS 2getVT-Exception occurred: $e'); // } finally { // setState(() { // isLoadingVehicleType = false; // }); // } // } Future getBroker() async { print('getBroker called'); setState(() { isLoadingBroker = 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(() { isLoadingBroker = false; }); } } Future getStaffDetailsForEnquiryAssignment(int id) async { print('getStaffDetailsForEnquiryAssignment called By handler'); setState(() { isLoadingStaffEnqAssign = true; }); try { // final response = await apiService.fetchStaffUserList(id, role); final response = await apiService.fetchStaffListForEnquiryAssignDropDown( managerId, id, roleId, ); if (response['status'] == 'success') { print('getStaffDetailsForEnquiryAssignment - ${response['data']}'); setState(() { getStaffDetailsDataEnqAsgn = List>.from( response['data'], ); print('API Data - $getStaffDetailsDataEnqAsgn'); filteredStaffDataEnqAsgn = List.from(getStaffDetailsDataEnqAsgn); print('originalData - $filteredStaffDataEnqAsgn'); }); } else { getStaffDetailsDataEnqAsgn = []; filteredStaffDataEnqAsgn = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoadingStaffEnqAssign = false; }); } } @override Widget build(BuildContext context) { return Form( key: _formKey, child: Wrap( crossAxisAlignment: WrapCrossAlignment.center, spacing: 12, runSpacing: 12, children: [ buildEnquiryCreatedOn(context), buildSelectStaffMem(context), buildAgentName(context, fromHeader: false), buildInsurer(context), buildBroker(context), buildInsuredName(context), buildVehicleNumber(context), buildEmail(context), buildPhNumber(context), buildRemarks(context), // buildVehicleType(context), Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: [ IconButton( tooltip: 'Save', padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 14, minHeight: 24), icon: const Icon( Icons.check, color: Colors.green, size: 20, // smaller icon ), splashRadius: 14, // onPressed: () { if (!_formKey.currentState!.validate()) return; widget.onSave(widget.selectId); }, ), IconButton( tooltip: 'Close', padding: EdgeInsets.zero, constraints: const BoxConstraints(minWidth: 14, minHeight: 24), icon: const Icon( Icons.close, color: Colors.indigo, size: 20, // smaller icon ), splashRadius: 14, // onPressed: widget.onClose, ), ], ), ], ), ); } Widget buildEnquiryCreatedOn(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Received Date', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( width: MediaQuery.of(context).size.width * 0.10, child: Stack( alignment: Alignment.centerRight, children: [ // 🔹 Your existing field ThemedFormField( controller: controllers['enquiry_created_on']!, hintText: 'Select Date', borderColor: Color(0XFF6366F1), textColr: Color(0XFF6366F1), enableBorderWidth: 0.5, bordedRad: 5, errFieldHgt: 10, errFieldFont: 0, isdense: true, readOnly: true, validator: (value) { if (fieldErrors['enquiry_created_on'] != null && fieldErrors['enquiry_created_on']!.isNotEmpty) { return fieldErrors['enquiry_created_on']; } return Validators.requiredField( value, "enquiry created on"); }, ), // 🔥 Independent calendar button Positioned( right: 4, child: InkWell( onTap: () async { await _pickDate(context); }, child: Padding( padding: const EdgeInsets.all(6.0), child: Icon( Icons.calendar_month, color: Color(0XFF6366F1), size: 18, ), ), ), ), ], ), ), ], ); } Future _pickDate(BuildContext context) async { DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime(1900), lastDate: DateTime(2100), ); if (picked != null) { setState(() { String formatted = DateFormat('dd-MM-yyyy').format(picked); controllers['enquiry_created_on']!.text = formatted; // clear error after select fieldErrors['enquiry_created_on'] = ''; }); } } Widget buildAgentName(BuildContext context, {fromHeader = true}) { Map? selectedAgntName = filteredAgentData.firstWhere( (item) => item['id'].toString() == widget.selectedAgent, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Partner', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( width: MediaQuery.of(context).size.width * 0.08, height: 30, child: DropdownSearch>( key: dropDownKeyAgent, selectedItem: selectedAgntName.isNotEmpty ? selectedAgntName : null, items: (filter, infiniteScrollProps) async { if (filter.isEmpty) { return filteredAgentData; } return filteredAgentData.where((item) { return item['name'].toString().toLowerCase().contains( filter.toLowerCase(), ); }).toList(); }, 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() : "", // ✅ FIXED style: GoogleFonts.poppins( fontSize: 11, color: Color(0XFF6366F1), ), overflow: TextOverflow.ellipsis, maxLines: 1, softWrap: false, ), ), decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Partner Name", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0XFF6366F1), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0XFF6366F1), 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, style: GoogleFonts.inter(fontSize: 11, color: Colors.black), decoration: InputDecoration( contentPadding: EdgeInsets.all(1), filled: true, fillColor: Colors.white, hintText: "Partner Name", hintStyle: GoogleFonts.inter( fontSize: 10, 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: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( item['name'].toString(), style: GoogleFonts.inter( fontSize: 12, color: Colors.black, ), ), Text( item['agent_code'].toString(), style: GoogleFonts.inter( fontSize: 11, color: Colors.grey, ), ), ], ), ); }, ), onChanged: (val) { if (val != null) { print("Selected Partner : ${val['name']}"); print("Id: ${val['id']}"); widget.onAgentChanged?.call(val['id']); // widget.selectedAgent = val['id']; // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } Widget buildVehicleNumber(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Vehicle Number', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( width: MediaQuery.of(context).size.width * 0.08, child: ThemedFormField( controller: controllers['regNo']!, hintText: 'Vehicle Number', borderColor: Color(0XFF6366F1), textColr: Color(0XFF6366F1), enableBorderWidth: 0.5, bordedRad: 5, errFieldHgt: 10, errFieldFont: 0, isdense: true, inputFormatters: [ UpperCaseTextFormatter(), // 👈 custom formatter for uppercase FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9- ]')), ], onChanged: (val) async { print('Vehicle - $val'); final res = await apiService.CheckDuplicate(context, val); print('Vehicle res- $res'); if (res["message"] != null && res["message"] != "") { ToastHelper.showErrorToast(context, res['message']); setState(() { fieldErrors['regNo'] = res['message']; // store API message }); // 🔥 store backend message } else { setState(() { fieldErrors['regNo'] = res['message']; // store API message }); } }, validator: (value) { // Show backend validation message if (fieldErrors['regNo'] != null && fieldErrors['regNo']!.isNotEmpty) { return fieldErrors['regNo']; // show API message } return Validators.requiredField(value, "regNo"); }, // widthNone: true, ), ), ], ); } Widget buildInsuredName(BuildContext context, {fromHeader = true}) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Insured', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( width: fromHeader ? MediaQuery.of(context).size.width * 0.1 : MediaQuery.of(context).size.width * 0.08, child: ThemedFormInlineField( controller: widget.controllers['name']!, hintText: 'Insured Name', textColr: Color(0XFF6366F1), // errorText: fieldErrors['name'], borderColor: Color(0XFF6366F1), isdense: true, // validator: (value) => Validators.requiredField(value, "name"), widthNone: true, ), ), ], ); } Widget buildEmail(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Email', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( width: MediaQuery.of(context).size.width * 0.1, child: ThemedFormField( controller: widget.controllers['email']!, borderColor: Color(0XFF6366F1), textColr: Color(0XFF6366F1), hintText: 'Email', bordedRad: 5, enableBorderWidth: 0.5, // errFieldHgt: 10, // errFieldFont: 0, isdense: true, 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.16, ), ), ], ); } Widget buildPhNumber(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Mobile', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( width: MediaQuery.of(context).size.width * 0.1, child: ThemedFormField( controller: widget.controllers['mobile']!, borderColor: Color(0XFF6366F1), textColr: Color(0XFF6366F1), hintText: 'Mobile', enableBorderWidth: 0.5, bordedRad: 5, isdense: true, 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 buildRemarks(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Remarks', style: _subLabelTimeStyle), SizedBox(height: 5), ThemedFormField( // maxLength: 500, enableBorderWidth: 0.5, hintText: 'Remarks', controller: widget.controllers['remarks']!, borderColor: Color(0XFF6366F1), textColr: Color(0XFF6366F1), bordedRad: 5, verticalPad: 10, horizonalPad: 10, isdense: true, // keyboardType: TextInputType.multiline, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.1, ), ], ); } Widget buildSelectStaffMem(ctx) { Map? selectedVehicle; try { selectedVehicle = filteredStaffDataEnqAsgn.firstWhere( (item) => item['id'].toString() == widget.selectedStaff, ); } catch (e) { selectedVehicle = null; // ✅ fallback } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Assigned To', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( height: 30, width: MediaQuery.of(context).size.width * 0.08, child: DropdownSearch>( key: dropDownSelectStaffKey, // selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, selectedItem: selectedVehicle, items: (filter, infiniteScrollProps) async { if (filter.isEmpty) { return filteredStaffDataEnqAsgn; } return filteredStaffDataEnqAsgn.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; // }, 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), ), ), decoratorProps: DropDownDecoratorProps( decoration: AppInputDecorations.dropdownDecoration( label: "Select Staff Member", ).copyWith( filled: true, fillColor: Colors.white, // 👈 makes the dropdown input white isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0XFF6366F1), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0XFF6366F1), width: 0.5, ), ), contentPadding: EdgeInsets.symmetric( horizontal: 8, vertical: 6, ), ), ), dropdownBuilder: (context, selectedItem) => Align( alignment: Alignment.centerLeft, child: Text( selectedItem != null ? selectedItem['name'].toString() : "", style: GoogleFonts.poppins( fontSize: 11, color: Color(0XFF6366F1), ), overflow: TextOverflow.ellipsis, maxLines: 1, softWrap: false, ), ), 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, style: GoogleFonts.inter(fontSize: 11, color: Colors.black), decoration: InputDecoration( contentPadding: EdgeInsets.all(1), filled: true, fillColor: Colors.white, hintText: "Search Staff ...", 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: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item['name'].toString(), style: GoogleFonts.inter( fontSize: 12, color: Colors.black, ), ), Text( "(${item['today_assigned']} / ${item['total_pending']})", style: GoogleFonts.poppins( fontSize: 10, color: Colors.blueGrey.shade200, ), ), ], ), ); }, ), onChanged: (val) { if (val != null) { print("Selected Staff : ${val['name']}"); print("Id: ${val['id']}"); // widget.selectedStaffName = val['name']; // widget.selectedStaff = val['id']; widget.onStaffChanged?.call(val['id']); // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } Widget buildInsurer(BuildContext context, {fromHeader = true}) { Map? selectedInsurerd = filteredInsurersData.firstWhere( (item) => item['id'].toString() == widget.selectedInsurer, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Insurer', style: _subLabelTimeStyle), SizedBox(height: 5), Container( height: 30, width: fromHeader ? MediaQuery.of(context).size.width * 0.1 : MediaQuery.of(context).size.width * 0.08, child: DropdownSearch>( key: dropDownKeyInsurerEnqAsgn, selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null, // items: (filter, infiniteScrollProps) { // return filteredInsurersData; // }, 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: Color(0XFF6366F1), ), 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(0XFF6366F1), width: 0.5, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0XFF6366F1), width: 0.5, ), ), contentPadding: EdgeInsets.symmetric( horizontal: 8, vertical: 6, ), ), ), popupProps: PopupProps.menu( fit: FlexFit.loose, constraints: BoxConstraints(maxHeight: 200), menuProps: MenuProps( backgroundColor: Colors.white, // 👈 sets dropdown background to white ), showSearchBox: true, searchFieldProps: TextFieldProps( style: GoogleFonts.inter(fontSize: 11, color: Colors.black), autofocus: true, decoration: InputDecoration( contentPadding: EdgeInsets.all(1), filled: true, fillColor: Colors.white, hintText: "Search Insurer...", 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['short_name'].toString(), style: GoogleFonts.inter(fontSize: 12, color: Colors.black), ), ); }, // constraints: BoxConstraints(), ), onChanged: (val) { if (val != null) { print("Selected Insurer : ${val['name']}"); print("Id: ${val['id']}"); // selectedInsurer = val['id']; widget.onInsurerChanged?.call(val['id']); // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } // Widget buildVehicleType(BuildContext context, {fromHeader = true}) { // Map? selectedVehicleTyped = filteredVehicleData.firstWhere( // (item) => item['vehicle_type_id'].toString() == widget.selectedVehicleType, // orElse: () => {}, // ); // // return Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Text('Vehicle Type', style: _subLabelTimeStyle), // SizedBox(height: 5), // Container( // height: 30, // width: fromHeader // ? MediaQuery.of(context).size.width * 0.1 // : MediaQuery.of(context).size.width * 0.08, // child: DropdownSearch>( // key: dropDownKeyVehicleTypeEnqAsgn, // selectedItem: selectedVehicleTyped.isNotEmpty ? selectedVehicleTyped : null, // // items: (filter, infiniteScrollProps) { // // return filteredInsurersData; // // }, // items: (filter, infiniteScrollProps) async { // if (filter.isEmpty) { // return filteredVehicleData; // } // return filteredVehicleData.where((item) { // return item['vehicle_type'].toString().toLowerCase().contains( // filter.toLowerCase(), // ); // }).toList(); // }, // // itemAsString: (val) => val['vehicle_type'].toString(), // what to show // compareFn: (item, selectedItem) => // item['vehicle_type'].toString() == selectedItem['vehicle_type'].toString(), // // // 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['vehicle_type'].toString() // : "", // style: GoogleFonts.poppins( // fontSize: 11, // color: Color(0XFF6366F1), // ), // overflow: TextOverflow.ellipsis, // maxLines: 1, // softWrap: false, // ), // ), // decoratorProps: DropDownDecoratorProps( // decoration: // AppInputDecorations.dropdownDecoration( // label: "Vehicle 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(0XFF6366F1), // width: 0.5, // ), // ), // enabledBorder: OutlineInputBorder( // borderRadius: BorderRadius.circular(5), // borderSide: const BorderSide( // color: Color(0XFF6366F1), // width: 0.5, // ), // ), // contentPadding: EdgeInsets.symmetric( // horizontal: 8, // vertical: 6, // ), // ), // ), // // popupProps: PopupProps.menu( // fit: FlexFit.loose, // constraints: BoxConstraints(maxHeight: 200), // menuProps: MenuProps( // backgroundColor: // Colors.white, // 👈 sets dropdown background to white // ), // showSearchBox: true, // searchFieldProps: TextFieldProps( // style: GoogleFonts.inter(fontSize: 11, color: Colors.black), // // autofocus: true, // decoration: InputDecoration( // contentPadding: EdgeInsets.all(1), // 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 // ), // ), // ), // 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: 12, color: Colors.black), // ), // ); // }, // // constraints: BoxConstraints(), // ), // // onChanged: (val) { // if (val != null) { // print("Selected vehicle_type : ${val['vehicle_type']}"); // print("Id: ${val['id']}"); // // selectedInsurer = val['id']; // widget.onVehicleTypeChanged?.call(val['id']); // // controllers['agentId']?.text = val['agent_code']; // // agentId = agent['id']; // } // }, // ), // ), // ], // ); // } Widget buildBroker(BuildContext context) { Map? selectedBrokers = filteredBrokerData.firstWhere( (item) => item['id'].toString() == widget.selectedBroker, orElse: () => {}, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Broker', style: _subLabelTimeStyle), SizedBox(height: 5), SizedBox( height: 30, width: MediaQuery.of(context).size.width * 0.07, 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: Color(0XFF6366F1), ), overflow: TextOverflow.ellipsis, maxLines: 1, softWrap: false, ), ), 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(0XFF6366F1), width: 0.1, ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: const BorderSide( color: Color(0XFF6366F1), 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, style: GoogleFonts.inter(fontSize: 11, color: Colors.black), 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), ), ); }, // constraints: BoxConstraints(), ), onChanged: (val) { if (val != null) { print("Selected Broker : ${val['name']}"); print("Id: ${val['id']}"); // selectedBroker = val['id']; widget.onBrokerChanged?.call(val['id']); // controllers['agentId']?.text = val['agent_code']; // agentId = agent['id']; } }, ), ), ], ); } final _subLabelTimeStyle = GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.w400, color: Color(0XFF6366F1), ); }