Merge branch 'master' of bitbucket.org:jubilian/nhance_partner

This commit is contained in:
venba-Inspriron-3558 2025-10-09 17:28:49 +05:30
commit 652c66c1fb
8 changed files with 932 additions and 235 deletions

File diff suppressed because one or more lines are too long

View File

@ -555,7 +555,7 @@ class ApiService {
}
Future<Map<String, dynamic>> findEnqQuotePolicyView(id) async {
// print(_token);
print('findEnqQuotePolicyView - $id');
if (_token == null) {
await _initializeToken();
}

View File

@ -99,7 +99,7 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
"email": controllers["email"]?.text,
"reg_no": controllers["regNo"]?.text,
"vehicle_type_id": selectedVehicleType,
"insurer_id": selectedInsurer,
// "insurer_id": selectedInsurer,
// "rc_file_name": "rc_doc.pdf",
// "id_proof_file_name": "id_proof.pdf",
// "previous_policy_file_name": "previous_policy.pdf",
@ -596,21 +596,24 @@ class EnquiryTabState extends ConsumerState<EnquiryTab> {
_buildResponsiveRow(
context,
buildVehicleType(context),
buildInsurer(context),
),
isMobile ? SizedBox(height: 5) : SizedBox(height: 20),
_buildResponsiveRow(
context,
// buildInsurer(context),
buildUploadRCDocument(context),
),
isMobile ? SizedBox(height: 5) : SizedBox(height: 20),
_buildResponsiveRow(
context,
// buildUploadRCDocument(context),
buildUploadIDDocument(context),
buildUploadPolicyDocument(context),
),
isMobile ? SizedBox(height: 5) : SizedBox(height: 20),
_buildResponsiveRow(
context,
buildUploadPolicyDocument(context),
// buildUploadPolicyDocument(context),
buildRemarks(context),
SizedBox.shrink(),
),
],
),

File diff suppressed because it is too large Load Diff

View File

@ -287,7 +287,7 @@ class EnquiryStaffState extends ConsumerState<EnquiryStaff> {
regNum,
) {
return [
if (roleId == 'manager' && data['status'] != 'Quotation Created') ...[
if (roleId == 'manager' && data['status'] == 'Awaiting Quotation') ...[
Material(
color: Colors.transparent,
child: InkWell(

View File

@ -250,7 +250,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
selectedEnquiryId = enquiryData['id'];
print('selectedEnquiryId- $selectedEnquiryId');
controllers["regNum"]?.text = enquiryData['reg_no'];
controllers["insurer"]?.text = enquiryData['insurer_name'];
// controllers["insurer"]?.text = enquiryData['insurer_name'];
});
}
@ -266,6 +266,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
if (quotationAcceptedData != null) {
if (!mounted) return;
setState(() {
controllers["insurer"]?.text = quotationAcceptedData?['insurer_name'];
acceptedQuotationId = quotationAcceptedData?['id']?.toString() ?? '';
controllers["idv"]?.text =
quotationAcceptedData?['insured_declared_value']?.toString() ??
@ -764,7 +765,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
// 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
final path =
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -805,7 +806,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
// 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
final path =
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -842,7 +843,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
// 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
final path =
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -882,7 +883,7 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
final path =
'api/quotation/downloadAdditionalUploadedFile?id=$acceptedQuotationId';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -1207,6 +1208,19 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
controllers['startDate']?.text = DateFormat(
'dd-MM-yyyy',
).format(date);
// auto set end date (1 year later - 1 day if needed)
final endDate = DateTime(
date.year + 1,
date.month,
date.day,
).subtract(const Duration(days: 1)); // optional: subtract 1 day
controllers['endDate']?.text = DateFormat(
'dd-MM-yyyy',
).format(endDate);
print("Auto-set End Date: $endDate");
// controllers['date']?.text = date as String;
},
),
@ -1227,13 +1241,75 @@ class PolicyScreenState extends ConsumerState<PolicyScreen> {
: MediaQuery.of(context).size.width * 0.26,
txtheight: 50,
// backgroundColor: const Color(0xFFECECEC),
validator: (value) => Validators.requiredField(value, "date"),
// validator: (value) => Validators.requiredField(value, "date"),
validator: (value) {
if (value == null || value.isEmpty) {
return "Required";
}
final startDateControllerText = controllers['startDate']?.text;
if (startDateControllerText == null ||
startDateControllerText.isEmpty) {
return "Select start date first";
}
final startDate = DateFormat(
'dd-MM-yyyy',
).parse(startDateControllerText);
final endDate = DateFormat('dd-MM-yyyy').parse(value);
if (endDate.isBefore(startDate)) {
return "End date cannot be before start date";
}
// Minimum end date = start date + 1 year - 1 day (or just +1 year)
final minEndDate = DateTime(
startDate.year + 1,
startDate.month,
startDate.day,
);
if (endDate.isBefore(minEndDate)) {
return "End date must be at least 1 year from start date";
}
return null;
// final startDateControllerText = controllers['startDate']?.text;
// if (startDateControllerText == null ||
// startDateControllerText.isEmpty) {
// return "Select start date first";
// }
//
// final startDate = DateFormat(
// 'dd-MM-yyyy',
// ).parse(startDateControllerText);
// final endDate = DateFormat('dd-MM-yyyy').parse(value);
//
// if (endDate.isBefore(startDate)) {
// return "End date cannot be before start date";
// }
//
// final expectedEndDate = DateTime(
// startDate.year + 1,
// startDate.month,
// startDate.day,
// ).subtract(const Duration(days: 1));
//
// if (endDate != expectedEndDate) {
// return "End date must be exactly 1 year from start date";
// }
//
// return null; // valid
},
controller: controllers['endDate']!,
onDateSelected: (date) {
print("Picked Date: $date");
controllers['endDate']?.text = DateFormat(
'dd-MM-yyyy',
).format(date);
_formKey.currentState?.validate();
// controllers['date']?.text = date as String;
},
),

View File

@ -46,6 +46,10 @@ class createQuotatDialogState extends State<createQuotatDialog> {
String? selectedFileNames;
List<Map<String, dynamic>> getInsurersData = [];
List<Map<String, dynamic>> filteredInsurersData = [];
String? selectedInsurer;
bool isLoading = false;
late TextEditingController controller;
Map<String, TextEditingController> controllers = {};
@ -59,6 +63,9 @@ class createQuotatDialogState extends State<createQuotatDialog> {
final GlobalKey<DropdownSearchState<Map<String, dynamic>>> dropDownKey =
GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
final GlobalKey<DropdownSearchState<Map<String, dynamic>>>
dropDownKeyInsurer = GlobalKey<DropdownSearchState<Map<String, dynamic>>>();
List<String> tabHeader = ['idv', 'premium_Amount'];
List<Map<String, dynamic>> getInsuranceTypeData = [];
@ -71,6 +78,7 @@ class createQuotatDialogState extends State<createQuotatDialog> {
final data = {
"enquiry_id": widget.selectedEnquiryId,
"insured_declared_value": controllers["idv"]?.text,
"insurer_id": selectedInsurer,
"premium_amount": controllers["premium_Amount"]?.text,
"insurance_plan_type_id": selectedInsPlanType,
// "additional_uploaded_file_name": "extra_doc.pdf",
@ -91,6 +99,7 @@ class createQuotatDialogState extends State<createQuotatDialog> {
// 🔹 Init logic here (API calls, token fetch, etc.)
_initializeToken();
getInsuranceType();
getInsurers();
updateData();
}
@ -126,6 +135,9 @@ class createQuotatDialogState extends State<createQuotatDialog> {
.selectedQuotationFrmListdata!['insurance_plan_type_id']
?.toString();
selectedInsurer =
widget.selectedQuotationFrmListdata!['insurer_id']?.toString() ?? '';
String? apiDocPath =
widget.selectedQuotationFrmListdata!["additional_uploaded_file_name"];
if (apiDocPath != null && apiDocPath.isNotEmpty) {
@ -143,6 +155,37 @@ class createQuotatDialogState extends State<createQuotatDialog> {
}
}
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> getInsuranceType() async {
print('getClaimList called');
setState(() {
@ -383,6 +426,7 @@ class createQuotatDialogState extends State<createQuotatDialog> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildIdv(context),
buildInsurer(context),
buildInsurancePlanType(context),
buildPremiumAmnt(context),
buildDocuments(context),
@ -420,6 +464,97 @@ class createQuotatDialogState extends State<createQuotatDialog> {
);
}
Widget buildInsurer(BuildContext context) {
Map<String, dynamic>? selectedInsurerd = filteredInsurersData.firstWhere(
(item) => item['id'].toString() == selectedInsurer,
orElse: () => {},
);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Insurer *', style: _textStyle),
SizedBox(height: 10),
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: Color(
0xFFEDF6F5,
), // 👈 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 buildPremiumAmnt(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -159,7 +159,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
selectedEnquiryId = enquiryData['id'];
print('selectedEnquiryId- $selectedEnquiryId');
controllers["regNum"]?.text = enquiryData['reg_no'];
controllers["insurer"]?.text = enquiryData['insurer_name'];
// controllers["insurer"]?.text = enquiryData['insurer_name'];
});
}
@ -194,7 +194,9 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
originalData = getQuotationData;
filteredData = List.from(originalData);
blockKey = getQuotationData.any((item) => item['status'] == 'Accepted');
blockKey = getQuotationData.any(
(item) => item['status'] == 'Accepted',
);
print('blockKey- $blockKey');
// print('originalData - $getClaimPolicies');
});
@ -339,8 +341,8 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
),
SizedBox(height: 15),
registerNumber(context),
SizedBox(height: 16),
insurer(context),
// SizedBox(height: 16),
// insurer(context),
SizedBox(height: 16),
buildDocRC(context, isMobile),
@ -376,13 +378,13 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
registerNumber(context),
Spacer(),
insurer(context),
Spacer(),
SizedBox(width: 10),
// insurer(context),
// Spacer(),
buildDocRC(context, isMobile),
Spacer(),
SizedBox(width: 10),
buildDocIdProof(context, isMobile),
Spacer(),
SizedBox(width: 10),
buildDocPrevPolicy(context, isMobile),
],
),
@ -392,72 +394,73 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
],
const SizedBox(height: 20),
if(!blockKey)...[
Container(
padding: EdgeInsets.only(right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
// print('Export');
setState(() {
selectedQuotationFrmListId = null;
selectedQuotationFrmListData = null;
});
if (!blockKey) ...[
Container(
padding: EdgeInsets.only(right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
// print('Export');
setState(() {
selectedQuotationFrmListId = null;
selectedQuotationFrmListData = null;
});
showDialog(
context: context,
builder: (ctx) => createQuotatDialog(
userId: userId,
selectedQuotationFrmListdata:
selectedQuotationFrmListData,
selectedQuotationFrmListId:
selectedQuotationFrmListId,
managerId: managerId,
selectedEnquiryId: selectedEnquiryId,
onSubmit: (value) {
debugPrint("New Endorsement: $value");
// enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
showDialog(
context: context,
builder: (ctx) => createQuotatDialog(
userId: userId,
selectedQuotationFrmListdata:
selectedQuotationFrmListData,
selectedQuotationFrmListId:
selectedQuotationFrmListId,
managerId: managerId,
selectedEnquiryId: selectedEnquiryId,
onSubmit: (value) {
debugPrint("New Endorsement: $value");
// enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber);
print(value);
if (value == 'Success') {
refresh();
}
print(value);
if (value == 'Success') {
refresh();
}
// Update claim list or call API
},
),
);
},
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Color(0xFF425B5B),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.add, color: Colors.white),
SizedBox(width: 10),
Text(
'Create New Quotation',
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 13,
),
// Update claim list or call API
},
),
],
);
},
child: Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Color(0xFF425B5B),
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.add, color: Colors.white),
SizedBox(width: 10),
Text(
'Create New Quotation',
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 13,
),
),
],
),
),
),
),
],
],
),
),
),
const SizedBox(height: 20),],
const SizedBox(height: 20),
],
//3RD SECTION (TABLE)
Container(
@ -529,7 +532,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
// 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
final path =
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -570,7 +573,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
// 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
final path =
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),
@ -607,7 +610,7 @@ class QuotationScreenState extends ConsumerState<QuotationScreen> {
// 'api/agent/downloadAgentIncentiveFile?id=$selectedId';
final path =
'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy';
apiService.getPdfDownload(context,path, selectedId);
apiService.getPdfDownload(context, path, selectedId);
},
child: Container(
padding: const EdgeInsets.all(8),