1580 lines
55 KiB
Dart
1580 lines
55 KiB
Dart
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<String, dynamic> controllers;
|
|
final List<Map<String, dynamic>> filteredStaffDataEnqAsgn;
|
|
final List<Map<String, dynamic>> 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<SubRowWidget> createState() => _SubRowWidgetState();
|
|
}
|
|
|
|
class _SubRowWidgetState extends ConsumerState<SubRowWidget> {
|
|
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<FormState>();
|
|
Map<String, String?> fieldErrors = {};
|
|
|
|
List<Map<String, dynamic>> getStaffData = [];
|
|
List<Map<String, dynamic>> originalData = [];
|
|
List<Map<String, dynamic>> 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<int, bool> rowExpanded = {};
|
|
Map<String, TextEditingController> controllers = {};
|
|
|
|
String formRebuildKey = UniqueKey().toString();
|
|
|
|
Map<int, bool> isEditingRow = {};
|
|
Map<int, Map<String, TextEditingController>> rowControllers = {};
|
|
|
|
//---------------------- Enquiry TAB Initializations Starts -------------------------------- //
|
|
|
|
List<Map<String, dynamic>> getVehicleTypeData = [];
|
|
List<Map<String, dynamic>> filteredVechicleData = [];
|
|
// List<Map<String, dynamic>> filteredVehicleData = [];
|
|
|
|
List<Map<String, dynamic>> getAgentListData = [];
|
|
List<Map<String, dynamic>> filteredAgentData = [];
|
|
|
|
List<Map<String, dynamic>> getInsurersData = [];
|
|
List<Map<String, dynamic>> filteredInsurersData = [];
|
|
|
|
List<Map<String, dynamic>> getPaymentModeData = [];
|
|
List<Map<String, dynamic>> filteredPaymentModeData = [];
|
|
|
|
List<Map<String, dynamic>> getInsuranceTypeData = [];
|
|
List<Map<String, dynamic>> filteredInsuranceData = [];
|
|
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
dropDownKeyInsurer = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyAgent =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
dropDownSelectPaymentModeKey =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
//---------------------- Assign Staff starts -------------------------------- //
|
|
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
dropDownKeyInsurerEnqAsgn =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
|
|
// final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
// dropDownKeyVehicleTypeEnqAsgn =
|
|
// GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKeyBroker =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
|
|
dropDownSelectStaffKey =
|
|
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
|
|
|
|
List<Map<String, dynamic>> getStaffDetailsDataEnqAsgn = [];
|
|
List<Map<String, dynamic>> filteredStaffDataEnqAsgn = [];
|
|
|
|
List<Map<String, dynamic>> getBrokerData = [];
|
|
List<Map<String, dynamic>> 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<void> loadPreferences() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
|
|
setState(() {
|
|
isActionable = prefs.getBool('isActionable') ?? false;
|
|
selectedSeconds = prefs.getInt('selectedSeconds') ?? 30;
|
|
|
|
_showFilterRow = true;
|
|
});
|
|
}
|
|
|
|
Future<void> 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<void> _initializeToken() async {
|
|
_token = await AuthService.getToken();
|
|
print("APISERTOKEN - $_token");
|
|
}
|
|
|
|
Future<void> 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<Map<String, dynamic>>.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<void> 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<Map<String, dynamic>>.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<void> 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<Map<String, dynamic>>.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<void> 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<Map<String, dynamic>>.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<void> 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<Map<String, dynamic>>.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<void> _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<String, dynamic>? 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<Map<String, dynamic>>(
|
|
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<String, dynamic>? 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<Map<String, dynamic>>(
|
|
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<String, dynamic>? 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<Map<String, dynamic>>(
|
|
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<String, dynamic>? 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<Map<String, dynamic>>(
|
|
// 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<String, dynamic>? 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<Map<String, dynamic>>(
|
|
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),
|
|
);
|
|
}
|