nhance_partner/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart

1322 lines
42 KiB
Dart

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<String, dynamic>? data;
EnquiryTab({super.key, this.data, this.id});
@override
ConsumerState<EnquiryTab> createState() => EnquiryTabState();
}
class EnquiryTabState extends ConsumerState<EnquiryTab> {
List<Map<String, dynamic>> dataVal = [];
final TextEditingController _searchController = TextEditingController();
late ApiService apiService;
final _formKey = GlobalKey<FormState>();
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>>>();
List<String> 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<String, TextEditingController> controllers = {};
List<Map<String, dynamic>> getVehicleTypeData = [];
List<Map<String, dynamic>> filteredVechicleData = [];
List<Map<String, dynamic>> getAgentListData = [];
List<Map<String, dynamic>> filteredAgentData = [];
List<Map<String, dynamic>> getInsurersData = [];
List<Map<String, dynamic>> filteredInsurersData = [];
Map<String, dynamic> 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<void> _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<void> 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<Map<String, dynamic>>.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<void> 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<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(() {
isLoading = false;
});
}
}
Future<void> 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<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(() {
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<void> 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<void> 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<void> attachFiles(http.MultipartRequest request) async {
Future<void> 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<void> createUserData(Map<String, dynamic> 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<String, dynamic>? 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<Map<String, dynamic>>(
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<String, dynamic>? 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<Map<String, dynamic>>(
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<String, dynamic>? 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<Map<String, dynamic>>(
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,
);
}