nhance_partner/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart
2026-06-09 09:11:30 +05:30

1346 lines
45 KiB
Dart

import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart' as ref;
import 'package:toastification/toastification.dart';
import '../../../../core/config/env.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 '../../../themes/indicators/customizd_file_upload.dart';
import '../../../themes/indicators/input_field_decoration.dart';
import '../../../themes/indicators/search_field_theme.dart';
import '../../../themes/indicators/text_field_theme.dart';
import '../../../widgets/policy_search_results_list.dart';
// 🔹 Custom Dialog Widget
class AddDialog extends StatefulWidget {
final String title;
final dynamic userId;
final dynamic managerId;
final dynamic role;
final void Function(String value) onSubmit;
// final dynamic policyNumber;
const AddDialog({
super.key,
required this.title,
required this.onSubmit,
required this.userId,
required this.managerId,
required this.role,
// this.policyNumber,
});
@override
State<AddDialog> createState() => _AddDialogState();
}
class _AddDialogState extends State<AddDialog> {
late ApiService apiService;
String? _token;
bool isLoading = false;
late TextEditingController controller;
Map<String, TextEditingController> controllers = {};
String? selectedClaimFileNames;
String? passportFileUrlFromApi;
String? selectedClaimId;
PlatformFile? docUploadedFile;
String? selectedFileNames;
String? passportEndorsFileUrlFromApi;
String? selectedEndorsId;
PlatformFile? docUploadedEndorsFile;
final _formKeyClaims = GlobalKey<FormState>();
final _formKeyEndrosment = GlobalKey<FormState>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
dropDownKeyEndorsement =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = ['policyNum', 'claimsDesc', 'remarks'];
final TextEditingController _vehicleSearchController =
TextEditingController();
final TextEditingController _policySearchController = TextEditingController();
final TextEditingController _searchStaffController = TextEditingController();
List<Map<String, dynamic>> getClaimsTypeData = [];
List<Map<String, dynamic>> filteredClaimsData = [];
List<Map<String, dynamic>> getEndrosmentType = [];
List<Map<String, dynamic>> filteredEndrosmentData = [];
String? selectedClaimsType;
String? selectedEndorsement;
String? selectedEndrosementPolicyFrom;
dynamic roleId;
List<Map<String, dynamic>> getPolicyData = [];
List<Map<String, dynamic>> originalData = [];
List<Map<String, dynamic>> filteredData = [];
List<Map<String, dynamic>> getPolicyListData = [];
List<Map<String, dynamic>> originalPolicyData = [];
List<Map<String, dynamic>> filteredPolicyData = [];
List<Map<String, dynamic>> getVehicleListData = [];
List<Map<String, dynamic>> originalVehicleData = [];
List<Map<String, dynamic>> filteredVehicleData = [];
final List<Map<String, dynamic>> policyFromOptions = [
{"policy_from": "Internal"},
{"policy_from": "External"},
];
Map<String, dynamic> claimsDetails() {
final data = {
"policy_number": controllers["policyNum"]?.text,
"claim_description": controllers["claimsDesc"]?.text,
"claim_type": selectedClaimsType,
// "manager_id": managerId,
"created_by": widget.userId,
};
return data;
}
Map<String, dynamic> endrosmentDetails() {
final data = {
"policy_number": controllers["policyNum"]?.text,
"endorsement_description": controllers["remarks"]?.text,
"endorsement_type": selectedEndorsement,
"manager_id": widget.managerId,
"created_by": widget.userId,
"policy_from": selectedEndrosementPolicyFrom,
};
return data;
}
@override
void initState() {
super.initState();
apiService = ApiService();
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
// controllers["policyNum"]?.text = widget.policyNumber;
print('userIFF - ${widget.userId}');
print('roleIFF - ${widget.role}');
Future.microtask(() {
// final id = ref.read(managerIdProvider);
// roleId = ref.read(userRoleProvider);
// userId = ref.read(userIdProvider);
if (widget.userId != null && widget.managerId != null) {
getStaffList(widget.managerId, widget.userId);
}
});
// 🔹 Init logic here (API calls, token fetch, etc.)
_initializeToken();
getClaimsType();
getEnroementType();
}
Future<void> getPolicyListSearchData(String val) async {
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchPolicySearch(val);
if (response['status'] == 'success' && response['data'] != null) {
final dataList = List<Map<String, dynamic>>.from(response['data']);
setState(() {
getPolicyListData = dataList;
originalPolicyData = dataList;
filteredPolicyData = List.from(originalPolicyData);
});
} else {
setState(() {
getPolicyListData = [];
originalPolicyData = [];
filteredPolicyData = [];
});
}
} catch (e) {
print('Exception occurred: $e');
setState(() {
getPolicyListData = [];
originalPolicyData = [];
filteredPolicyData = [];
});
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getVehicleListSearchData(String val) async {
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchVehicleSearch(val);
if (response['status'] == 'success') {
print('E113 => getStaffListData => ${response['data']}');
setState(() {
getVehicleListData = List<Map<String, dynamic>>.from(
response['data'],
);
originalVehicleData = getVehicleListData;
filteredVehicleData = List.from(originalVehicleData);
// print('originalData - $getClaimPolicies');
});
} else {
getVehicleListData = [];
originalVehicleData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getPolicyListSearchData1(val) async {
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchPolicySearch(val);
if (response['status'] == 'success') {
print('E113 => getStaffListData => ${response['data']}');
setState(() {
getPolicyListData = List<Map<String, dynamic>>.from(response['data']);
// filteredData = getPolicyData.where((item) {
// return (item['agent_name'] ?? '-').toLowerCase() ||
// (item['reg_no'] ?? '-').toLowerCase;
// }).toList();
originalPolicyData = getPolicyListData;
filteredPolicyData = List.from(originalPolicyData);
// print('originalData - $getClaimPolicies');
});
} else {
getPolicyListData = [];
originalPolicyData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getStaffList(
dynamic managerId,
role, {
String fromDate = '',
String toDate = '',
}) async {
print('D68 => Fns called => $managerId | $role');
setState(() {
isLoading = true;
});
final id = int.parse(managerId);
// FORCE BOTH VALUES TO STRING
final String managerIdStr = managerId?.toString() ?? '';
final String roleStr = role?.toString() ?? '';
try {
final response = await apiService.fetchPolicyDataOnlyList(
managerIdStr,
roleStr,
roleStr,
fromDate: controllers['startDate']?.text ?? '',
toDate: controllers['endDate']?.text ?? '',
selectedStaffId: widget.userId ?? '',
);
if (response['status'] == 'success') {
final data = response['data'];
print('D81 => getStaffListData => ${response['data']}');
final fromDate = response['from_date'] ?? '';
final toDate = response['to_date'] ?? '';
print('FromDate : $fromDate');
print('ToDate : $toDate');
setState(() {
controllers['startDate']?.text = fromDate;
controllers['endDate']?.text = toDate;
if (data is List) {
// Already a list of maps
getPolicyData = List<Map<String, dynamic>>.from(data);
} else if (data is Map) {
// Single object, wrap in a list
getPolicyData = [Map<String, dynamic>.from(data)];
} else {
getPolicyData = [];
}
// getStaffData = List<Map<String, dynamic>>.from(response['data']);
originalData = getPolicyData;
filteredData = List.from(originalData);
// print('originalData - $getClaimPolicies');
});
} else {
getPolicyData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
void filterData(String query) {
print("FilterDAta - $query");
setState(() {
filteredData = getPolicyData.where((item) {
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
return (item['agent_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['reg_no'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insurer_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
);
}).toList();
});
}
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> getClaimsType() async {
print('getClaimList called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchMasterDropDown('Claim');
if (response['status'] == 200) {
print('getClaimsTypeData - ${response['data']}');
setState(() {
getClaimsTypeData = List<Map<String, dynamic>>.from(response['data']);
print('API Data - $getClaimsTypeData');
filteredClaimsData = List.from(getClaimsTypeData);
// print('originalData - $filteredClaimsData');
});
} else {
getClaimsTypeData = [];
filteredClaimsData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
Future<void> getEnroementType() async {
print('Insurers called');
setState(() {
isLoading = true;
});
try {
final response = await apiService.fetchMasterDropDown('Endorsement');
if (response['status'] == 200) {
print('getEnroementType - ${response['data']}');
setState(() {
getEndrosmentType = List<Map<String, dynamic>>.from(response['data']);
print('API Data - $getEndrosmentType');
filteredEndrosmentData = List.from(getEndrosmentType);
// print('originalData - $filteredEndrosmentData');
});
} else {
getEndrosmentType = [];
filteredEndrosmentData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoading = false;
});
}
}
void handleDone(val) {
print('val - $val');
if (val == 'Claims') {
if (!_formKeyClaims.currentState!.validate()) return;
setState(() {
if (_formKeyClaims.currentState!.validate()) {
claimsDetails();
final dataSet = claimsDetails();
print("dataSetAgent - $dataSet");
// print("managerId - $managerId ,userId - $userId ");
createUserData(dataSet, val);
} else {
// isDi sable = false;
}
});
}
else {
if (!_formKeyEndrosment.currentState!.validate()) return;
setState(() {
if (_formKeyEndrosment.currentState!.validate()) {
endrosmentDetails();
final dataSet = endrosmentDetails();
print("dataSetAgent - $dataSet");
// print("managerId - $managerId ,userId - $userId ");
createUserData(dataSet, val);
} else {
// isDisable = false;
}
});
}
}
Future<void> createUserData(data, val) async {
final endpoints = {
'Claims': 'claim/createClaim',
'Endorsement': 'endorsement/createEndorsement',
};
final String? path = endpoints[val];
final Uri uri = Uri.parse('${Env.apiUrl}$path');
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;
print("USerDAta - $data");
// userData.forEach((key, value) {
// request.fields[key] = value.toString();
// print("✅ Encoded travel_details2: ${request.fields[key]}");
// });
data.forEach((key, value) {
// if (key != 'certificate_file_name') {
request.fields[key] = value.toString();
print("✅ Encoded $key: ${request.fields[key]}");
// }
});
if (val == 'Claims') {
// Attach file if selected
if (docUploadedFile != null) {
try {
if (docUploadedFile!.bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'claim_file_name',
docUploadedFile!.bytes!,
filename: docUploadedFile!.name,
);
request.files.add(multipartFile);
}
// else if (docUploadedFile!.path != null) {
// final multipartFile = await http.MultipartFile.fromPath(
// 'certificate_file_name',
// docUploadedFile!.path!,
// filename: docUploadedFile!.name,
// );
// request.files.add(multipartFile);
// }
print("📎 File attached: ${docUploadedFile!.name}");
} catch (e) {
print("❌ Failed to attach file: $e");
}
}
} else {
// Attach file if selected
if (docUploadedEndorsFile != null) {
try {
if (docUploadedEndorsFile!.bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'endorsement_file_name',
docUploadedEndorsFile!.bytes!,
filename: docUploadedEndorsFile!.name,
);
request.files.add(multipartFile);
}
// else if (docUploadedEndorsFile!.path != null) {
// final multipartFile = await http.MultipartFile.fromPath(
// 'endorsement_file_name',
// docUploadedEndorsFile!.path!,
// filename: docUploadedEndorsFile!.name,
// );
// request.files.add(multipartFile);
// }
print("📎 File attached: ${docUploadedEndorsFile!.name}");
} catch (e) {
print("❌ Failed to attach file: $e");
}
}
}
print(" Sending request with fields: ${request.fields}");
try {
final streamedResponse = await request.send();
final response = await http.Response.fromStream(streamedResponse);
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
if (response.statusCode == 200 || response.statusCode == 201) {
print("✅ Partner submitted successfully!");
print("Response: ${response.body}");
ToastHelper.showSuccessToast(context, 'Saved Successfully');
Navigator.of(context).pop();
widget.onSubmit("success");
} else if (response.statusCode == 403) {
await apiService.clearLocalStorageAndRedirect();
} else {
final responseBody = jsonDecode(response.body);
dynamic msg = responseBody['data'];
print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}");
ToastHelper.showErrorToast(context, 'Failed To Save');
}
} catch (e) {
print("🔥 Error submitting user: $e");
}
}
@override
Widget build(BuildContext context) {
return SelectionArea(
child: AlertDialog(
backgroundColor: Colors.white,
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header row
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.title,
style: GoogleFonts.inter(
color: const Color(0xFF374141),
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
GestureDetector(
onTap: () => Navigator.pop(context),
child: Container(
padding: const EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: const Color(0xFFF1F1F1),
borderRadius: BorderRadius.circular(5.0),
),
child: Tooltip(
message: 'Close',
child: const Icon(Icons.close, size: 18),
),
),
),
],
),
const SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
ThemedSearchField(
hintText: 'Search By Vehicle Number',
backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30,
controller: _vehicleSearchController,
onChanged: (val) async {
if (val.isNotEmpty) {
await getVehicleListSearchData(val);
} else {
setState(() {
// filteredVehicleData = List.from(originalVehicleData);
filteredVehicleData.clear();
});
}
},
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
if (filteredVehicleData.isNotEmpty)
SizedBox(
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
child: PolicySearchResultsList(
rows: filteredVehicleData,
fromVehicle: true,
onSelected: (vehicle) {
setState(() {
controllers['policyNum']?.text =
PolicySearchUtils.policyNumberFromRow(vehicle);
_vehicleSearchController.text =
PolicySearchUtils.vehicleInputValueOnSelect(
vehicle,
);
filteredVehicleData.clear();
});
},
),
),
],
),
SizedBox(width: 15),
Column(
children: [
ThemedSearchField(
hintText: 'Search By Policy Number',
backgroundColor: Color(0xFFFFFFFF),
txtHeight: 30,
controller: _policySearchController,
onChanged: (val) async {
if (val.isNotEmpty) {
await getPolicyListSearchData(val);
} else {
setState(() {
// filteredPolicyData = List.from(originalPolicyData);
filteredPolicyData.clear();
});
}
},
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
// Policy Search Results
if (filteredPolicyData.isNotEmpty)
Container(
width:
MediaQuery.of(context).size.width * 0.26, // optional
height: 150,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.blueGrey.shade100),
borderRadius: BorderRadius.circular(5),
),
child: ListView.builder(
itemCount: filteredPolicyData.length,
itemBuilder: (context, index) {
final policy = filteredPolicyData[index];
return InkWell(
onTap: () {
setState(() {
controllers['policyNum']?.text =
policy['policy_number'];
filteredPolicyData.clear();
});
},
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 3,
horizontal: 8,
),
// color: Colors.amber,
child: Text(
policy['policy_number'] ?? '-',
style: _textStyle1,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
);
// ListTile(
// dense: true, // ← reduces row height
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// vertical: 2,
// ),
// subtitle: Text(
//
// style: _textStyle1,
// ),
// onTap: () {
// setState(() {
//
// // populate other fields as needed
// });
// },
// );
},
),
),
],
),
],
),
const SizedBox(height: 10),
const SizedBox(height: 16),
// 🔹 Switch content dynamically
widget.title == 'Claims' ? claims(context) : endorsement(context),
],
),
actions: [
GestureDetector(
onTap: () {
handleDone(widget.title);
// widget.onSubmit(controller.text.trim());
// Navigator.of(context).pop();
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 25.0, vertical: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: const Color(0xFF425B5B),
),
child: const Text('Save', style: TextStyle(color: Colors.white)),
),
),
],
) );
}
// 🔹 Example: Claims widget
Widget claims(BuildContext context) {
return Form(
key: _formKeyClaims,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildClaimType(context),
SizedBox(width: 15),
buildPolicyNumber(context),
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildUploadDocumentClaims(context),
SizedBox(width: 15),
buildClaimsDesc(context),
],
),
],
),
);
}
// 🔹 Example: Endorsement widget
Widget endorsement(BuildContext context) {
return Form(
key: _formKeyEndrosment,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildEndrosType(context),
SizedBox(width: 15),
buildEndrosPolicyFrom(context),
],
),
SizedBox(height: 10),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildUploadDocumentClaims(context),
SizedBox(width: 15),
buildPolicyNumber(context),
],
),
SizedBox(height: 10),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
buildEndrosRemarks(context),
SizedBox(width: 15),
],
),
],
),
);
}
// ------------------------- Claims Part -----------------------------------
Widget buildPolicyNumber(context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Policy Number *", style: _textStyle),
SizedBox(height: 10),
ThemedFormField(
controller: controllers['policyNum']!,
backgroundColor: Color(0xFFEDF6F5),
readOnly: true,
validator: (value) => Validators.requiredField(value, "name"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
),
],
);
}
Widget buildClaimsDesc(context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Claims Description ", style: _textStyle),
SizedBox(height: 10),
ThemedFormField(
backgroundColor: Color(0xFFEDF6F5),
controller: controllers['claimsDesc']!,
// txtheight: 45,
validator: (value) => Validators.requiredField(value, "claimsDesc"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
keyboardType: TextInputType.multiline,
),
],
);
}
Widget buildClaimType(context) {
Map<String, dynamic>? selectedVehicle = filteredClaimsData.firstWhere(
(item) => item['id'].toString() == selectedClaimsType,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Claims Type *", style: _textStyle),
SizedBox(height: 10),
Container(
color: Colors.white,
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 filteredClaimsData;
},
itemAsString: (val) => val['claim_type'].toString(),
compareFn: (item, selectedItem) =>
item['id'] == selectedItem['id'], // ✅ compare by id
validator: (val) {
if (val == null) {
return "Required"; // ✅ error message
}
return null;
},
decoratorProps: DropDownDecoratorProps(
decoration:
AppInputDecorations.dropdownDecoration(
label: "Select Claims Type",
).copyWith(
filled: true,
fillColor: Color( 0xFFEDF6F5,), // 👈 makes the dropdown input white
isDense: true, // 👈 Makes the field compact
contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 0), // 👈 Vertical 0 helps center the text
),
),
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 Claims Type...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected ClaimsType : ${val['claim_type']}");
print("Id: ${val['id']}");
selectedClaimsType = val['id'];
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
Widget buildUploadDocumentClaims(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Upload Document", style: _textStyle),
SizedBox(height: 10),
ThemedUploadField(
backgroundColor: Color(0xFFEDF6F5),
hintText: selectedClaimFileNames ?? "Upload Document",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
onFileSelected: (fileName, file) {
print("Picked file: $fileName (${file.size} bytes)");
setState(() {
docUploadedFile = file;
});
},
),
// Column(
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// ThemedUploadField(
// hintText: selectedClaimFileNames ?? "Upload Document",
// txtwidth: MediaQuery.of(context).size.width * 0.26,
// onFileSelected: (fileName, file) {
// print("Picked file: $fileName (${file.size} bytes)");
// setState(() {
// docUploadedFile = file;
// });
// },
// ),
// // const SizedBox(height: 5),
// //
// // if (docUploadedFile != null || passportFileUrlFromApi != null)
// // Container(
// // // color: Colors.white,
// // child: Row(
// // children: [
// // GestureDetector(
// // onTap: () => apiService.downloadFile(
// // apiUrl:
// // 'agent/downloadAgentCertificateFile?agent_id=$selectedClaimId',
// // apiId: selectedClaimId,
// // localFile: docUploadedFile,
// // fileName: selectedClaimFileNames,
// // ),
// // child: Container(
// // padding: const EdgeInsets.all(5),
// // decoration: BoxDecoration(
// // borderRadius: BorderRadius.circular(5),
// // color: Color(0xFF425B5B),
// // // color: Colors.green.shade300,
// // ),
// // 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),
// // ],
// // ),
// // ),
// // ),
// // ],
// // ),
// // ),
// ],
// ),
],
);
}
//------------------------- Endrosment Part -----------------------------------
Widget buildEndrosType(context) {
Map<String, dynamic>? selectedEndorsementd = filteredEndrosmentData
.firstWhere(
(item) => item['id'].toString() == selectedEndorsement,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Endorsement Type *", style: _textStyle),
SizedBox(height: 10),
Container(
color: Colors.white,
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// height: 40,
child: DropdownSearch<Map<String, dynamic>>(
key: dropDownKeyEndorsement,
selectedItem: selectedEndorsementd.isNotEmpty
? selectedEndorsementd
: null,
items: (filter, infiniteScrollProps) {
return filteredEndrosmentData;
},
itemAsString: (val) =>
val['endorsement_type'].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 Endorsement Type",
).copyWith(
filled: true,
fillColor: Color( 0xFFEDF6F5,), // 👈 makes the dropdown input white
isDense: true, // 👈 Makes the field compact
contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 0), // 👈 Vertical 0 helps center the text
),
),
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 Endorsement Type...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
// constraints: BoxConstraints(),
),
onChanged: (val) {
if (val != null) {
print("Selected Endorsement : ${val['endorsement_type']}");
print("Id: ${val['id']}");
selectedEndorsement = val['id'];
// controllers['agentId']?.text = val['agent_code'];
// agentId = agent['id'];
}
},
),
),
],
);
}
Widget buildEndrosPolicyFrom(context) {
// Find the selected item from the static list based on your variable
Map<String, dynamic> selectedEndorsementPF = policyFromOptions.firstWhere(
(item) => item['policy_from'].toString() == selectedEndrosementPolicyFrom,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Policy From *", style: _textStyle),
const SizedBox(height: 10),
Container(
color: Colors.white,
width: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
child: DropdownSearch<Map<String, dynamic>>(
// Use a unique key for this dropdown
key: const ValueKey("policyFromDropdown"),
selectedItem: selectedEndorsementPF.isNotEmpty
? selectedEndorsementPF
: null,
items: (filter, infiniteScrollProps) {
return policyFromOptions; // Use the static list
},
itemAsString: (val) => val['policy_from'].toString(),
compareFn: (item, selectedItem) =>
item['policy_from'] == selectedItem['policy_from'],
// --- REQUIRED VALIDATOR ---
validator: (val) {
if (val == null || val.isEmpty) {
return "Required";
}
return null;
},
decoratorProps: DropDownDecoratorProps(
decoration: AppInputDecorations.dropdownDecoration(
label: "Select Policy From",
).copyWith(
filled: true,
fillColor: const Color(0xFFEDF6F5), // 👈 makes the dropdown input white
isDense: true, // 👈 Makes the field compact
contentPadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 0), // 👈 Vertical 0 helps center the text
),
),
popupProps: PopupProps.menu(
fit: FlexFit.loose,
constraints: const BoxConstraints(maxHeight: 150), // Shorter for 2 items
menuProps: const MenuProps(
backgroundColor: Colors.white,
),
showSearchBox: true, // Disabled search as there are only 2 items
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search Policy From...",
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
), // 👈 Normal border
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.white,
width: 1.5,
), // 👈 Focused border
),
),
),
),
onChanged: (val) {
if (val != null) {
setState(() {
print("Selected Policy From: ${val['policy_from']}");
selectedEndrosementPolicyFrom = val['policy_from'];
});
}
},
),
),
],
);
}
Widget buildEndrosRemarks(context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Remarks *", style: _textStyle),
SizedBox(height: 10),
ThemedFormField(
backgroundColor: Color(0xFFEDF6F5),
controller: controllers['remarks']!,
validator: (value) => Validators.requiredField(value, "remarks"),
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
// keyboardType: TextInputType.multiline,
// txtheight: 45,
),
],
);
}
Widget buildUploadDocumentEndorsment(context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Upload Document", style: _textStyle),
SizedBox(width: 10),
ThemedUploadField(
backgroundColor: Color(0xFFEDF6F5),
hintText: selectedFileNames ?? "Upload Document",
txtwidth: ResponsiveLayout.isMobile(context)
? null
: MediaQuery.of(context).size.width * 0.26,
onFileSelected: (fileName, file) {
print("Picked file: $fileName (${file.size} bytes)");
setState(() {
docUploadedEndorsFile = file;
});
},
),
// Column(
// mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// ThemedUploadField(
// hintText: selectedFileNames ?? "Upload Document",
// txtwidth: MediaQuery.of(context).size.width * 0.26,
// onFileSelected: (fileName, file) {
// print("Picked file: $fileName (${file.size} bytes)");
// setState(() {
// docUploadedEndorsFile = file;
// });
// },
// ),
// // const SizedBox(height: 5),
// //
// // if (docUploadedEndorsFile != null || passportEndorsFileUrlFromApi != null)
// // Container(
// // // color: Colors.white,
// // child: Row(
// // children: [
// //
// // GestureDetector(
// // onTap: () => apiService.downloadFile(
// // apiUrl:
// // 'agent/downloadAgentCertificateFile?agent_id=$selectedEndorsId',
// // apiId: selectedEndorsId,
// // localFile: docUploadedEndorsFile,
// // fileName: selectedFileNames,
// // ),
// // child: Container(
// // padding: const EdgeInsets.all(5),
// // decoration: BoxDecoration(
// // borderRadius: BorderRadius.circular(5),
// // color: Color(0xFF425B5B),
// // // color: Colors.green.shade300,
// // ),
// // child: Row(
// // children: const [
// // Text(
// // "Download",
// // style: TextStyle(
// // fontSize: 12,
// // fontWeight: FontWeight.w200,
// // color: Colors.white,
// // ),
// // ),
// // SizedBox(width: 5),
// // Icon(Icons.download, size: 13, color: Colors.white),
// // ],
// // ),
// // ),
// // ),
// // ],
// // ),
// // ),
// ],
// ),
],
);
}
// ------------------- STyle ---------------------------------
static final TextStyle _textStyle = TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
);
static final TextStyle _textStyle1 = TextStyle(
fontSize: 9,
fontWeight: FontWeight.w400,
);
}