diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 34f8b4c..1c5e8da 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -91,13 +91,15 @@ class ApiService { } } - Future getPdfDownload(path, id) async { + Future getPdfDownload1(path, id) async { // final url = Uri.parse( // 'https://venbait.in/nhance/partner/dev/api/agent/downloadAgentCertificateFile?agent_id=1', // ); - final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path'); - // final token = await getToken(); + print('GetDownload'); + final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path'); + print('GetDownload - $url'); + await _initializeToken(); if (_token == null) { throw Exception('Token not found. Please log in.'); @@ -130,28 +132,84 @@ class ApiService { throw Exception('Error parsing response: $e'); } } else if (response.statusCode == 404) { - // showDialog( - // context: context, - // builder: (BuildContext context) { - // return AlertDialog( - // title: Text('File not found.'), - // // content: Text('File not found.'), - // actions: [ - // TextButton( - // child: Text('OK'), - // onPressed: () { - // Navigator.of(context).pop(); // Close the dialog - // }, - // ), - // ], - // ); - // }, - // ); + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('File not found.'), + // content: Text('File not found.'), + actions: [ + TextButton( + child: Text('OK'), + onPressed: () { + Navigator.of(context).pop(); // Close the dialog + }, + ), + ], + ); + }, + ); } else { throw Exception('Failed to load plans'); } } + Future getPdfDownload(String path, String id) async { + print('getPdfDownload 1'); + final url = Uri.parse('https://venbait.in/nhance/partner/dev/$path'); + await _initializeToken(); + print('getPdfDownload 2'); + if (_token == null) throw Exception('Token not found. Please log in.'); + + final headers = { + 'Authorization': 'Bearer $_token', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + + final response = await _makeGethttpRequest(url, headers); + print('getPdfDownload 3'); + if (response.statusCode == 200) { + final blob = html.Blob([response.bodyBytes]); + final blobUrl = html.Url.createObjectUrlFromBlob(blob); + print('getPdfDownload $blobUrl'); + // --- filename resolution --- + String fileName = 'download_$id'; + print('getPdfDownloadfileName $fileName'); + final contentDisp = response.headers['content-disposition']; + print('getPdfDownloadcontentDisp $contentDisp'); + if (contentDisp != null && contentDisp.contains('filename=')) { + print('getPdfDownloadcontentDisp..1'); + fileName = contentDisp.split('filename=')[1].replaceAll('"', ''); + print('getPdfDownloadcontentDisp..2'); + } else { + print('getPdfDownloadcontentDisp..3'); + // fallback: URL or id + fileName = path.split('/').last; + if (id != null) fileName = '${id}_$fileName'; + } + final anchor = html.AnchorElement(href: blobUrl) + ..setAttribute('download', fileName) + ..click(); + print('getPdfDownloadcontentDisp..4'); + html.Url.revokeObjectUrl(blobUrl); + } else if (response.statusCode == 404) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('File not found.'), + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ); + } else { + throw Exception('Failed to download file'); + } + } + Future downloadFile({ required String? apiUrl, required PlatformFile? localFile, @@ -176,7 +234,8 @@ class ApiService { } } else if (apiUrl != null) { print("Download from API: $apiUrl"); - await getPdfDownload(apiUrl, apiId); + print("Download from API: $apiId!"); + await getPdfDownload(apiUrl, apiId!); } else { print("⚠️ No file available to download"); } @@ -516,6 +575,21 @@ class ApiService { return response; } + Future> findSingleClaimData(id) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + final url = Uri.parse('${Env.apiUrl}claim/ClaimList?policy_number=$id'); + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + // ----------------------------------- ENDORSEMENT ------------------------------------------------- Future> fetchEndorsementList(int id, role) async { @@ -549,6 +623,23 @@ class ApiService { return response; } + Future> findSingleEnrosmentData(id) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + final url = Uri.parse( + '${Env.apiUrl}endorsement/endorsementList?policy_number=$id', + ); + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + // --------------------------------- MASTER DATA ---------------------------------------------- Future> fetchMasterDropDown(String val) async { diff --git a/lib/data/utils/validators.dart b/lib/data/utils/validators.dart index 46da37d..48d373d 100644 --- a/lib/data/utils/validators.dart +++ b/lib/data/utils/validators.dart @@ -3,7 +3,8 @@ import 'package:flutter/cupertino.dart'; class Validators { static String? requiredField(String? value, String label) { if (value == null || value.trim().isEmpty) { - return "$label is required"; + return "Required"; + // return "$label is required"; } return null; } diff --git a/lib/presentation/layouts/main_layout.dart b/lib/presentation/layouts/main_layout.dart index fad7f95..fbbfac2 100644 --- a/lib/presentation/layouts/main_layout.dart +++ b/lib/presentation/layouts/main_layout.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:http/http.dart' as ref; import 'package:nhance_partner/core/routing/routes.dart'; import 'package:nhance_partner/data/services/auth_service.dart'; +import '../providers/manager_provider.dart'; import '../screens/UserManagement/Profile/profile_web.dart'; import '../widgets/custom_action_popup.dart'; import '../widgets/topbar.dart'; @@ -26,7 +28,7 @@ class MainLayout extends StatelessWidget { title: title, isMobile: true, onBack: () { - Navigator.pop(context); + // Navigator.pop(context); }, onNotifications: () { debugPrint("Notifications tapped"); @@ -42,7 +44,8 @@ class MainLayout extends StatelessWidget { } else if (index == 1) { context.go(AppRoutes.profile); } else if (index == 2) { - context.go(AppRoutes.tabEnquiry); + // ref.read(enquiryIdProvider.notifier).state = null; + context.go(AppRoutes.enquiryLst); } }, ), diff --git a/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart b/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart index 78396f0..1cc497b 100644 --- a/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart +++ b/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart @@ -65,6 +65,8 @@ class EnquiryTabState extends ConsumerState { String? selectedIdProof; String? selectedPrevPolicy; + String? selectedRCFileName; + String? rcFileUrlFromApi; String? idProofFileUrlFromApi; String? prevPolicyFileUrlFromApi; @@ -73,7 +75,7 @@ class EnquiryTabState extends ConsumerState { bool isLoading = false; String? selectedVehicleType; - int? selectedVehicleTypeId; + // int? selectedVehicleTypeId; String? selectedInsurer; Map controllers = {}; @@ -222,13 +224,17 @@ class EnquiryTabState extends ConsumerState { selectedVehicleType = data['vehicle_type_id'] ?? ''; selectedInsurer = data['insurer_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 = - rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet + docUploadedRCFile = null; + // docUploadedRCFile = + // rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet } else { selectedRCFile = null; // no UI file shown rcFileUrlFromApi = null; @@ -240,7 +246,8 @@ class EnquiryTabState extends ConsumerState { if (idProofPath != null && idProofPath.isNotEmpty) { selectedIdProof = idProofPath.split('/').last; idProofFileUrlFromApi = idProofPath; // ✅ FIXED → correct variable - docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?; + docUploadedIDProof = null; + // docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?; } else { selectedIdProof = null; idProofFileUrlFromApi = null; @@ -253,7 +260,8 @@ class EnquiryTabState extends ConsumerState { selectedPrevPolicy = prevPolicyPath.split('/').last; prevPolicyFileUrlFromApi = prevPolicyPath; // ✅ FIXED → correct variable - docUploadedPrevPolicy = prevPolicyFileUrlFromApi as PlatformFile?; + docUploadedPrevPolicy = null; + // docUploadedPrevPolicy = prevPolicyFileUrlFromApi as PlatformFile?; } else { selectedPrevPolicy = null; prevPolicyFileUrlFromApi = null; @@ -271,6 +279,22 @@ class EnquiryTabState extends ConsumerState { 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; @@ -331,36 +355,6 @@ class EnquiryTabState extends ConsumerState { ); } - Future attachFiles1(http.MultipartRequest request) async { - Future addFile(PlatformFile? file, String fieldName) async { - if (file == null) return; - try { - if (file.bytes != null) { - final multipartFile = http.MultipartFile.fromBytes( - fieldName, - file.bytes!, - filename: file.name, - ); - request.files.add(multipartFile); - } else if (file.path != null) { - final multipartFile = await http.MultipartFile.fromPath( - fieldName, - file.path!, - filename: file.name, - ); - request.files.add(multipartFile); - } - print("📎 File attached: ${file.name} → $fieldName"); - } catch (e) { - print("❌ Failed to attach $fieldName: $e"); - } - } - - await addFile(docUploadedRCFile, 'rc_file_name'); - await addFile(docUploadedIDProof, 'id_proof_file_name'); - await addFile(docUploadedPrevPolicy, 'previous_policy_file_name'); - } - Future createUserData(Map userData) async { final bool isUpdating = widget.data != null && widget.id != 'tab' && widget.id != 'null'; @@ -397,16 +391,17 @@ class EnquiryTabState extends ConsumerState { // request.fields[key] = value.toString(); // print("✅ Encoded travel_details2: ${request.fields[key]}"); // }); - + await attachFiles(request); userData.forEach((key, value) { - if (key != 'certificate_file_name') { + 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 - await attachFiles(request); // request.fields['agent_id'] = selectedId.toString(); @@ -423,7 +418,13 @@ class EnquiryTabState extends ConsumerState { print("✅ Agent submitted successfully!"); ToastHelper.showSuccessToast(context, 'Saved Enquiry'); print("Response: ${response.body}"); - context.go(AppRoutes.tabEnquiry); + + if (isUpdating) { + context.go(AppRoutes.tabEnquiry); + } else { + ref.read(enquiryIdProvider.notifier).state = null; + context.go(AppRoutes.enquiryLst); + } } else { print("❌ Submission failed. Status: ${response.statusCode}"); print("Body: ${response.body}"); @@ -432,9 +433,9 @@ class EnquiryTabState extends ConsumerState { context: context, builder: (BuildContext context) { return AlertDialog( - title: Text("Agent Creation Failed"), + title: Text("Enquiry Creation Failed"), content: Text( - "There was a problem in creating user. Please try again.", + "There was a problem in creating enquiry. Please try again.", ), actions: [ TextButton( @@ -455,6 +456,7 @@ class EnquiryTabState extends ConsumerState { @override Widget build(BuildContext context) { + bool isMobile = ResponsiveLayout.isMobile(context); return Container( // color: Colors.green, decoration: BoxDecoration( @@ -463,14 +465,16 @@ class EnquiryTabState extends ConsumerState { ), width: MediaQuery.of(context).size.width, // height: MediaQuery.of(context).size.height * 0.8, - padding: EdgeInsets.all(26.0), + padding: isMobile + ? EdgeInsets.only(left: 14.0, right: 14.0) + : EdgeInsets.all(26.0), child: Column( children: [ - // Row(children: [Expanded(child: buildFormFields(context))]), - Expanded( - child: SingleChildScrollView(child: buildFormFields(context)), - ), - + isMobile + ? Row(children: [Expanded(child: buildFormFields(context))]) + : Expanded( + child: SingleChildScrollView(child: buildFormFields(context)), + ), const SizedBox(height: 20), Row( @@ -499,27 +503,29 @@ class EnquiryTabState extends ConsumerState { } Widget buildFormFields(BuildContext context) { + bool isMobile = ResponsiveLayout.isMobile(context); return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildResponsiveRow(context, buildName(context), buildEmail(context)), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + + isMobile ? SizedBox(height: 5) : SizedBox(height: 20), _buildResponsiveRow( context, buildPhNumber(context), buildId(context), ), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + isMobile ? SizedBox(height: 5) : SizedBox(height: 20), _buildResponsiveRow( context, buildVehicleType(context), buildInsurer(context), ), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + isMobile ? SizedBox(height: 5) : SizedBox(height: 20), _buildResponsiveRow( context, @@ -527,7 +533,7 @@ class EnquiryTabState extends ConsumerState { buildUploadIDDocument(context), ), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + isMobile ? SizedBox(height: 5) : SizedBox(height: 20), _buildResponsiveRow( context, buildUploadPolicyDocument(context), @@ -621,9 +627,10 @@ class EnquiryTabState extends ConsumerState { Widget buildName(BuildContext context) { return buildResponsiveField( - label: "Full Name ", + label: "Full Name *", field: ThemedFormField( controller: controllers['name']!, + validator: (value) => Validators.requiredField(value, "name"), txtwidth: ResponsiveLayout.isMobile(context) ? null @@ -634,7 +641,7 @@ class EnquiryTabState extends ConsumerState { Widget buildEmail(BuildContext context) { return buildResponsiveField( - label: "Email", + label: "Email *", field: ThemedFormField( controller: controllers['email']!, validator: (value) => Validators.email(value, "email"), @@ -647,7 +654,7 @@ class EnquiryTabState extends ConsumerState { Widget buildPhNumber(BuildContext context) { return buildResponsiveField( - label: "Phone Number", + label: "Phone Number *", field: ThemedFormField( controller: controllers['mobile']!, validator: (value) => Validators.phone(value, "phNumber"), @@ -660,7 +667,7 @@ class EnquiryTabState extends ConsumerState { Widget buildId(BuildContext context) { return buildResponsiveField( - label: "Registration Number", + label: "Registration Number *", field: ThemedFormField( controller: controllers['regNo']!, validator: (value) => Validators.requiredField(value, "regNo"), @@ -680,9 +687,12 @@ class EnquiryTabState extends ConsumerState { ); return buildResponsiveField( - label: "Vehicle Type", + label: "Vehicle Type *", field: Container( - color: Colors.white, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -693,6 +703,12 @@ class EnquiryTabState extends ConsumerState { 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) => @@ -756,9 +772,12 @@ class EnquiryTabState extends ConsumerState { orElse: () => {}, ); return buildResponsiveField( - label: "Insurer", + label: "Insurer *", field: Container( - color: Colors.white, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), width: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -773,6 +792,12 @@ class EnquiryTabState extends ConsumerState { 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( @@ -860,14 +885,14 @@ class EnquiryTabState extends ConsumerState { 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', - ), + // IconButton( + // onPressed: onRemove, + // icon: const Icon( + // Icons.remove_circle_outline_rounded, + // color: Colors.redAccent, + // ), + // tooltip: 'Remove Upload', + // ), GestureDetector( onTap: onDownload, child: Container( @@ -904,7 +929,10 @@ class EnquiryTabState extends ConsumerState { Text(label, style: _textStyle), const SizedBox(height: 8), uploadWidget, - downloadRow, + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [downloadRow], + ), const SizedBox(height: 16), ], ); @@ -931,12 +959,12 @@ class EnquiryTabState extends ConsumerState { Widget buildUploadRCDocument(BuildContext context) { return buildResponsiveUploadField( - label: "Upload RC Document", + label: "Upload RC Document *", hintText: selectedRCFile, onFileSelected: (fileName, file) { setState(() { docUploadedRCFile = file; - // selectedFileNames = fileName; + selectedRCFileName = fileName; }); }, showDownload: docUploadedRCFile != null || rcFileUrlFromApi != null, @@ -944,7 +972,7 @@ class EnquiryTabState extends ConsumerState { setState(() { docUploadedRCFile = null; rcFileUrlFromApi = null; - // selectedFileNames = null; + selectedRCFileName = null; }); }, onDownload: () => apiService.downloadFile( @@ -952,29 +980,17 @@ class EnquiryTabState extends ConsumerState { apiUrl: 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc', - apiId: null, + apiId: selectedId.toString(), + localFile: docUploadedRCFile, fileName: 'RC', ), ); } - // Widget buildUploadIDDocument(BuildContext context) { - // return buildResponsiveUploadField( - // label: "Upload ID Proof", - // hintText: selectedIdProof, - // onFileSelected: (fileName, file) { - // print("File picked: $fileName"); - // setState(() { - // docUploadedIDProof = file; - // }); - // }, - // ); - // } - Widget buildUploadIDDocument(BuildContext context) { return buildResponsiveUploadField( - label: "Upload ID Proof", + label: "Upload ID Proof *", hintText: selectedIdProof, onFileSelected: (fileName, file) { setState(() { @@ -995,26 +1011,13 @@ class EnquiryTabState extends ConsumerState { apiUrl: 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof', - apiId: null, - localFile: docUploadedRCFile, + apiId: selectedId.toString(), + localFile: docUploadedIDProof, fileName: 'Id_Proof', ), ); } - // Widget buildUploadPolicyDocument(BuildContext context) { - // return buildResponsiveUploadField( - // label: "Upload Previous Policy", - // hintText: selectedPrevPolicy, - // onFileSelected: (fileName, file) { - // print("File picked: $fileName"); - // setState(() { - // docUploadedPrevPolicy = file; - // }); - // }, - // ); - // } - Widget buildUploadPolicyDocument(BuildContext context) { return buildResponsiveUploadField( label: "Upload Previous Policy", @@ -1039,7 +1042,7 @@ class EnquiryTabState extends ConsumerState { apiUrl: 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy', - apiId: null, + apiId: selectedId.toString(), localFile: docUploadedPrevPolicy, fileName: 'Previous_Policy', ), @@ -1052,6 +1055,7 @@ class EnquiryTabState extends ConsumerState { field: ThemedFormField( maxLength: 500, controller: controllers['remarks']!, + keyboardType: TextInputType.multiline, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, diff --git a/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart b/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart index f667aae..cceede1 100644 --- a/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart +++ b/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart @@ -1,52 +1,588 @@ +import 'dart:convert'; + +import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:toastification/toastification.dart'; -import 'package:flutter/material.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/input_field_decoration.dart'; +import '../../../themes/indicators/text_field_theme.dart'; -Future showAddDialog({ - required BuildContext context, - required String title, - required void Function(String value) onSubmit, -}) async { - final TextEditingController controller = TextEditingController(); +// 🔹 Custom Dialog Widget +class AddDialog extends StatefulWidget { + final String title; + final dynamic userId; + final void Function(String value) onSubmit; + final dynamic policyNumber; + const AddDialog({ + super.key, + required this.title, + required this.onSubmit, + required this.userId, + this.policyNumber, + }); - await showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text(title), - content: title == 'Claim' - ? claims() - : endorsement(), // 👈 conditional content - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text("Cancel"), - ), - ElevatedButton( - onPressed: () { - onSubmit(controller.text.trim()); - Navigator.of(context).pop(); - }, - child: const Text("Save"), - ), - ], + @override + State createState() => _AddDialogState(); +} + +class _AddDialogState extends State { + late ApiService apiService; + String? _token; + + bool isLoading = false; + late TextEditingController controller; + Map controllers = {}; + + final _formKeyClaims = GlobalKey(); + final _formKeyEndrosment = GlobalKey(); + final GlobalKey>> dropDownKey = + GlobalKey>>(); + final GlobalKey>> + dropDownKeyEndorsement = + GlobalKey>>(); + + List tabHeader = ['policyNum', 'claimsDesc', 'remarks']; + + List> getClaimsTypeData = []; + List> filteredClaimsData = []; + + List> getEndrosmentType = []; + List> filteredEndrosmentData = []; + + String? selectedClaimsType; + String? selectedEndorsement; + + Map 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 endrosmentDetails() { + final data = { + "policy_number": controllers["policyNum"]?.text, + "endorsement_description": controllers["remarks"]?.text, + "endorsement_type": selectedEndorsement, + // "manager_id": managerId, + "created_by": widget.userId, + }; + return data; + } + + @override + void initState() { + super.initState(); + apiService = ApiService(); + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + + controllers["policyNum"]?.text = widget.policyNumber; + // 🔹 Init logic here (API calls, token fetch, etc.) + _initializeToken(); + getClaimsType(); + getEnroementType(); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + Future 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>.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 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>.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 createUserData(data, val) async { + // final bool isUpdating = widget.id != null && widget.id != 'create'; + final String apiUrldata; + + apiUrldata = (val == 'Claims') + ? '${Env.apiUrl}claim/createClaim' + : '${Env.apiUrl}endorsement/createEndorsement'; + + // final token = await getToken(); // Fetch token + + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + print("data------- $data}"); + + try { + final response = await http.post( + Uri.parse(apiUrldata), + headers: { + 'Authorization': 'Bearer $_token', + 'Content-Type': 'application/json', + 'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }, + body: jsonEncode(data), // Convert map to JSON ); - }, - ); -} -Widget claims() { - return Container( - padding: const EdgeInsets.all(16), - color: Colors.redAccent, - child: const Text('Claims', style: TextStyle(color: Colors.white)), - ); -} + if (response.statusCode == 200) { + print("Staff submitted successfully!"); + print("Response: ${response.body}"); + ToastHelper.showSuccessToast(context, 'Saved Successfully'); + Navigator.of(context).pop(); -Widget endorsement() { - return Container( - padding: const EdgeInsets.all(16), - color: Colors.yellow, - child: const Text('Endorsement', style: TextStyle(color: Colors.black)), + widget.onSubmit("success"); + // context.go(AppRoutes.staffLst); + } 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 Staff: $e"); + } + } + + @override + void dispose() { + // controllers.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return 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: const Icon(Icons.close, size: 18), + ), + ), + ], + ), + + const SizedBox(height: 16), + + // 🔹 Switch content dynamically + widget.title == 'Claims' ? claims(context) : endorsement(context), + ], + ), + actions: [ + Center( + child: 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('Done', style: TextStyle(color: Colors.white)), + ), + ), + ), + ], + ); + } + + // 🔹 Example: Claims widget + Widget claims(BuildContext context) { + return Form( + key: _formKeyClaims, + child: Column( + children: [ + buildClaimType(context), + buildPolicyNumber(context), + buildClaimsDesc(context), + ], + ), + ); + } + + // 🔹 Example: Endorsement widget + Widget endorsement(BuildContext context) { + return Form( + key: _formKeyEndrosment, + child: Column( + children: [buildEndrosType(context), buildEndrosRemarks(context)], + ), + ); + } + + // ------------------------- 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), + 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']!, + 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? 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>( + 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 + ), + ), + + 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']; + } + }, + ), + ), + ], + ); + } + + // ------------------------- Endrosment Part ----------------------------------- + + Widget buildEndrosType(context) { + Map? 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>( + 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 + ), + ), + + 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 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, + ), + ], + ); + } + + // ------------------- STyle --------------------------------- + + static final TextStyle _textStyle = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, ); } diff --git a/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart b/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart index d1c3268..db40517 100644 --- a/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart +++ b/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart @@ -15,16 +15,26 @@ import '../../../providers/manager_provider.dart'; import '../../../themes/indicators/export_btn.dart'; import '../../../themes/indicators/search_field_theme.dart'; import '../../../themes/indicators/text_field_theme.dart'; +import '../../../widgets/custom_action_popup.dart'; +import '../policy_claims_endros/sub_claims.dart'; +import '../policy_claims_endros/sub_endrosment.dart'; class PolicyTab extends ConsumerStatefulWidget { final List>? data; + dynamic id; // const PolicyTab({super.key}); - const PolicyTab({super.key, this.data}); + PolicyTab({super.key, this.data, this.id}); @override ConsumerState createState() => PolicyTabState(); } class PolicyTabState extends ConsumerState { + final GlobalKey claimsKey = + GlobalKey(); + + final GlobalKey enrollKey = + GlobalKey(); + List> dataVal = []; final TextEditingController _searchController = TextEditingController(); @@ -38,13 +48,6 @@ class PolicyTabState extends ConsumerState { bool isLoading = false; List tabHeader = [ - 'name', - 'email', - 'mobile', - 'code', - 'address', - 'regNo', - 'regNum', 'insurer', 'idv', @@ -59,7 +62,7 @@ class PolicyTabState extends ConsumerState { String? _token; dynamic userId; dynamic managerId; - + dynamic selectedPolicyNumber; @override void initState() { super.initState(); @@ -74,7 +77,7 @@ class PolicyTabState extends ConsumerState { managerId = ref.watch(managerIdProvider); userId = ref.watch(userIdProvider); - getQuotationList(managerId); + getPolicyList(managerId); }); } @@ -83,8 +86,8 @@ class PolicyTabState extends ConsumerState { print("APISERTOKEN - $_token"); } - Future getQuotationList(int managerId) async { - print('getClaimList called MagId - $managerId'); + Future getPolicyList(int managerId) async { + print('getPolicyList called MagId - $managerId'); setState(() { isLoading = true; }); @@ -101,11 +104,14 @@ class PolicyTabState extends ConsumerState { // getQuotationData = List>.from(response['data']); originalData = getQuotationData; filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + updateData(filteredData); }); } else { getQuotationData = []; originalData = []; + filteredData = []; } } catch (e) { print('Exception occurred: $e'); @@ -116,228 +122,329 @@ class PolicyTabState extends ConsumerState { } } + void updateData(data) { + if (data != null && data is List && data.isNotEmpty) { + final record = data[0]; // get the first map + print('UPDID - $record'); + + setState(() { + selectedPolicyNumber = record['policy_number']?.toString() ?? ''; + controllers['regNum']?.text = record['reg_no']?.toString() ?? ''; + controllers['insurer']?.text = record['insurer_name']?.toString() ?? ''; + controllers['idv']?.text = + record['insured_declared_value']?.toString() ?? ''; + controllers['insurerName']?.text = + record['insured_name']?.toString() ?? ''; + controllers['policyNo']?.text = + record['policy_number']?.toString() ?? ''; + controllers['paymentMode']?.text = + record['payment_mode']?.toString() ?? ''; + controllers['premAmount']?.text = + record['premium_amount']?.toString() ?? ''; + controllers['planType']?.text = + record['insurance_plan_type']?.toString() ?? ''; + }); + } + } + @override Widget build(BuildContext context) { - return Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Column( - children: [ - 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: EdgeInsets.all(26.0), - child: Column( - children: [ - Container( - child: Row( + final isMobile = ResponsiveLayout.isMobile(context); + return isLoading + ? CircularProgressIndicator() + : Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: filteredData.isNotEmpty + ? SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( children: [ - Text( - 'Policy Details', - style: GoogleFonts.inter( - fontWeight: FontWeight.bold, - fontSize: 16, + 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.all(10.0) + : EdgeInsets.all(16.0), + child: Column( + children: [ + if (!ResponsiveLayout.isMobile(context)) ...[ + Container( + child: Row( + children: [ + Text( + 'Policy Details', + style: GoogleFonts.inter( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + if (!ResponsiveLayout.isMobile( + context, + )) ...[ + Spacer(), + buildDocPolicy(context, isMobile), - Spacer(), - GestureDetector( - onTap: () {}, - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: const Color(0xFF425B5B), - ), - child: Row( - children: const [ - Text( - "Download Policy", - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w200, - color: Colors.white, + SizedBox(width: 15), + buildDocReciept(context, isMobile), + ], + // GestureDetector( + // onTap: () { + // print("Upload ${widget.id}"); + // final selectedId = widget.id; + // // final path = + // // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + // final path = + // 'api/policy/downloadPolicyFile?policy_id=$selectedId&file_type=policy_payment_receipt'; + // apiService.getPdfDownload(path, selectedId); + // }, + // child: Container( + // padding: const EdgeInsets.all(8), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(5), + // color: const Color(0xFF425B5B), + // ), + // child: Row( + // children: const [ + // Text( + // "Download Receipt", + // style: TextStyle( + // fontSize: 12, + // fontWeight: FontWeight.w200, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 15), + // Icon( + // Icons.file_download_outlined, + // size: 16, + // color: Colors.white, + // ), + // ], + // ), + // ), + // ), + ], ), ), - SizedBox(width: 15), - Icon( - Icons.file_download_outlined, - size: 16, - color: Colors.white, - ), + const SizedBox(height: 20), ], - ), + SingleChildScrollView( + child: buildFormFields(context), + ), + + isMobile + ? SizedBox(height: 5) + : SizedBox(height: 20), + ], ), ), - - SizedBox(width: 15), - GestureDetector( - onTap: () {}, - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: const Color(0xFF425B5B), - ), - child: Row( - children: const [ - Text( - "Download Receipt", - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w200, - color: Colors.white, - ), + isMobile ? SizedBox(height: 5) : SizedBox(height: 20), + 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: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'More Information (optional)', + style: GoogleFonts.inter( + fontWeight: FontWeight.bold, + fontSize: 16, ), - SizedBox(width: 15), - Icon( - Icons.file_download_outlined, - size: 16, - color: Colors.white, + ), + if (!ResponsiveLayout.isMobile(context)) ...[ + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text('Claim', style: _headerStyle), + ), + SizedBox(width: 20), + Expanded( + child: buildMoreInfoSetClaims(context), + ), + ], ), ], - ), + + if (ResponsiveLayout.isMobile(context)) + Container( + padding: EdgeInsets.all(6.0), + decoration: BoxDecoration( + color: Color(0xFFF6FEFD), + + // color: Color(0xFFCBE6E2), + borderRadius: BorderRadius.circular(10.0), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 100, + child: Text( + 'Claim', + style: _headerStyle, + ), + ), + _actionClaims(context), + ], + ), + + SizedBox(width: 20), + buildMoreInfoSetClaims(context), + ], + ), + ), + + SizedBox(height: 10), + if (!ResponsiveLayout.isMobile(context)) + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text( + 'Endorsement', + style: _headerStyle, + ), + ), + SizedBox(width: 20), + Expanded( + child: buildMoreInfoSetEndrosment( + context, + ), + ), + ], + ), + + if (ResponsiveLayout.isMobile(context)) + Container( + padding: EdgeInsets.all(6.0), + decoration: BoxDecoration( + color: Color(0xFFF6FEFD), + + // color: Color(0xFFCBE6E2), + borderRadius: BorderRadius.circular(10.0), + ), + + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 100, + child: Text( + 'Endorsement', + style: _headerStyle, + ), + ), + _actionEnroll(context), + ], + ), + + SizedBox(width: 20), + buildMoreInfoSetEndrosment(context), + ], + ), + ), + // SizedBox(height: 10), + // Row( + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // GestureDetector( + // onTap: () { + // // handleSave(); + // }, + // child: Container( + // padding: EdgeInsets.symmetric( + // horizontal: 45.0, + // vertical: 8, + // ), + // + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular( + // 8.0, + // ), + // color: Color(0xFF425B5B), + // ), + // child: Text( + // 'Save', + // style: TextStyle(color: Colors.white), + // ), + // ), + // ), + // ], + // ), + // SizedBox(height: 30), + // _buildDataTable(context), + ], ), ), ], ), - ), - const SizedBox(height: 20), - SingleChildScrollView(child: buildFormFields(context)), + ) + : Center(child: Text('No Available Data')), + ); + } - const SizedBox(height: 20), - ], + Widget buildDocPolicy(BuildContext context, bool isMobile) { + return GestureDetector( + onTap: () { + print("Upload ${widget.id}"); + final selectedId = widget.id; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/policy/downloadPolicyFile?policy_id=$selectedId&file_type=policy_pdf'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + children: [ + const Text( + "Download Policy", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, ), ), - const SizedBox(height: 20), - 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: EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('More Information', style: _headerStyle), - Row( - children: [ - SizedBox( - width: 100, - child: Text('Claim', style: _headerStyle), - ), - SizedBox(width: 20), - Expanded( - child: Container( - padding: EdgeInsets.all(6.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10.0), - ), - - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container(child: buildClaimTable()), - IconButton( - onPressed: () { - showAddDialog( - context: context, - title: "Claim", - onSubmit: (value) { - print("New Claim: $value"); - // update claim list here - }, - ); - }, - icon: Icon(Icons.add), - ), - ], - ), - ), - ), - ], - ), - SizedBox(height: 10), - Row( - children: [ - SizedBox( - width: 100, - child: Text('Endorsement', style: _headerStyle), - ), - SizedBox(width: 20), - Expanded( - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(6.0), - ), - - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container(child: buildEndrosmentTable()), - IconButton( - onPressed: () { - showAddDialog( - context: context, - title: "Endorsement", - onSubmit: (value) { - print("New Claim: $value"); - // update claim list here - }, - ); - }, - icon: Icon(Icons.add), - ), - ], - ), - ), - ), - ], - ), - SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - GestureDetector( - onTap: () { - // handleSave(); - }, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 45.0, - vertical: 8, - ), - - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - color: Color(0xFF425B5B), - ), - child: Text( - 'Save', - style: TextStyle(color: Colors.white), - ), - ), - ), - ], - ), - // SizedBox(height: 30), - // _buildDataTable(context), - ], - ), + isMobile ? const Spacer() : const SizedBox(width: 15), + const Icon( + Icons.file_download_outlined, + size: 16, + color: Colors.white, ), ], ), @@ -345,7 +452,149 @@ class PolicyTabState extends ConsumerState { ); } + Widget buildDocReciept(BuildContext context, bool isMobile) { + return GestureDetector( + onTap: () { + print("Upload ${widget.id}"); + final selectedId = widget.id; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/policy/downloadPolicyFile?policy_id=$selectedId&file_type=policy_payment_receipt'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + children: [ + Text( + "Download Receipt", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, + ), + ), + isMobile ? const Spacer() : const SizedBox(width: 15), + Icon(Icons.file_download_outlined, size: 16, color: Colors.white), + ], + ), + ), + ); + } + + Widget buildMoreInfoSetClaims(BuildContext context) { + if (selectedPolicyNumber == null || selectedPolicyNumber!.isEmpty) { + return const Center(child: CircularProgressIndicator()); // or placeholder + } + return Container( + padding: ResponsiveLayout.isMobile(context) ? null : EdgeInsets.all(6.0), + decoration: ResponsiveLayout.isMobile(context) + ? null + : BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), + + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ClaimsSubList( + key: claimsKey, + policyNumber: selectedPolicyNumber, + ), + ), + if (!ResponsiveLayout.isMobile(context)) _actionClaims(context), + ], + ), + ); + } + + Widget buildMoreInfoSetEndrosment(BuildContext context) { + if (selectedPolicyNumber == null || selectedPolicyNumber!.isEmpty) { + return const Center(child: CircularProgressIndicator()); // or placeholder + } + return Container( + // padding: EdgeInsets.all(8.0), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(6.0), + // ), + padding: ResponsiveLayout.isMobile(context) ? null : EdgeInsets.all(6.0), + decoration: ResponsiveLayout.isMobile(context) + ? null + : BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: EndrosmentSubList( + key: enrollKey, + policyNumber: selectedPolicyNumber, + ), + ), + if (!ResponsiveLayout.isMobile(context)) _actionEnroll(context), + ], + ), + ); + } + + Widget _actionEnroll(BuildContext context) { + return IconButton( + onPressed: () { + showDialog( + context: context, + builder: (ctx) => AddDialog( + userId: userId, + title: "Endorsement", + policyNumber: selectedPolicyNumber, + onSubmit: (value) { + debugPrint("New Endorsement: $value"); + enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber); + + // Update claim list or call API + }, + ), + ); + }, + icon: Icon(Icons.add), + ); + } + + Widget _actionClaims(BuildContext context) { + return IconButton( + onPressed: () { + showDialog( + context: context, + builder: (ctx) => AddDialog( + userId: userId, + title: "Claims", + policyNumber: selectedPolicyNumber, + onSubmit: (value) { + debugPrint("New Claim: $value"); + claimsKey.currentState?.getClaimsList(selectedPolicyNumber); + + // Update claim list or call API + }, + ), + ); + }, + icon: Icon(Icons.add), + ); + } + Widget buildFormFields(BuildContext context) { + final isMobile = ResponsiveLayout.isMobile(context); return Form( key: _formKey, child: Column( @@ -356,28 +605,36 @@ class PolicyTabState extends ConsumerState { buildName(context), buildInsusrer(context), ), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + isMobile ? SizedBox(height: 5) : SizedBox(height: 10), _buildResponsiveRow( context, buildIdv(context), buildInsurdName(context), ), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + isMobile ? SizedBox(height: 5) : SizedBox(height: 10), _buildResponsiveRow( context, buildPolicyNum(context), buildPaymentMode(context), ), - if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), - + isMobile ? SizedBox(height: 5) : SizedBox(height: 10), _buildResponsiveRow( context, buildPlanType(context), buildPremiumAmount(context), ), + + isMobile ? SizedBox(height: 5) : SizedBox(height: 10), + if (ResponsiveLayout.isMobile(context)) + _buildResponsiveRow( + context, + buildDocPolicy(context, isMobile), + + buildDocReciept(context, isMobile), + ), ], ), ); @@ -390,7 +647,7 @@ class PolicyTabState extends ConsumerState { ) { if (ResponsiveLayout.isMobile(context)) { // Stack vertically - return Column(children: [first, const SizedBox(height: 2), second]); + return Column(children: [first, const SizedBox(height: 4), second]); } else { // Place side by side return Row( @@ -432,8 +689,8 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Registration Number", field: ThemedFormField( - controller: controllers['name']!, - validator: (value) => Validators.requiredField(value, "name"), + controller: controllers['regNum']!, + // validator: (value) => Validators.requiredField(value, "name"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -445,8 +702,7 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Insusrer", field: ThemedFormField( - controller: controllers['email']!, - validator: (value) => Validators.email(value, "email"), + controller: controllers['insurer']!, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -458,7 +714,7 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "IDV", field: ThemedFormField( - controller: controllers['mobile']!, + controller: controllers['idv']!, validator: (value) => Validators.phone(value, "phNumber"), txtwidth: ResponsiveLayout.isMobile(context) ? null @@ -471,8 +727,8 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Insured Name", field: ThemedFormField( - controller: controllers['mobile']!, - validator: (value) => Validators.phone(value, "phNumber"), + controller: controllers['insurerName']!, + // validator: (value) => Validators.phone(value, "phNumber"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -484,8 +740,8 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Policy Number", field: ThemedFormField( - controller: controllers['mobile']!, - validator: (value) => Validators.phone(value, "phNumber"), + controller: controllers['policyNo']!, + // validator: (value) => Validators.phone(value, "phNumber"), txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -497,8 +753,7 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Payment Mode", field: ThemedFormField( - controller: controllers['mobile']!, - validator: (value) => Validators.phone(value, "phNumber"), + controller: controllers['paymentMode']!, txtwidth: ResponsiveLayout.isMobile(context) ? null : MediaQuery.of(context).size.width * 0.26, @@ -510,7 +765,7 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Plan Type", field: ThemedFormField( - controller: controllers['mobile']!, + controller: controllers['planType']!, validator: (value) => Validators.phone(value, "phNumber"), txtwidth: ResponsiveLayout.isMobile(context) ? null @@ -523,7 +778,7 @@ class PolicyTabState extends ConsumerState { return buildResponsiveField( label: "Premium Amount", field: ThemedFormField( - controller: controllers['mobile']!, + controller: controllers['premAmount']!, validator: (value) => Validators.phone(value, "phNumber"), txtwidth: ResponsiveLayout.isMobile(context) ? null @@ -532,14 +787,6 @@ class PolicyTabState extends ConsumerState { ); } - Widget buildClaimTable() { - return Text('data'); - } - - Widget buildEndrosmentTable() { - return Text('data'); - } - static const _headerStyle = TextStyle( color: Colors.black, fontWeight: FontWeight.bold, @@ -549,4 +796,29 @@ class PolicyTabState extends ConsumerState { fontSize: 14, fontWeight: FontWeight.w600, ); + + static final _dataBold = TextStyle( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = TextStyle( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + static const _cardheaderStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static const _cardBodyStyle = TextStyle( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); } diff --git a/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart b/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart index bdb4c4d..7be52a0 100644 --- a/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart +++ b/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart @@ -45,6 +45,7 @@ class QuotationTabState extends ConsumerState { 'regNum', 'insurer', 'idv', + 'insuranceId', 'premAmount', 'planType', 'addit_doc', @@ -64,6 +65,7 @@ class QuotationTabState extends ConsumerState { String? selectedId; bool isLoading = false; bool isquotation = false; + bool showAction = false; Map controllers = {}; String? _token; @@ -78,13 +80,12 @@ class QuotationTabState extends ConsumerState { Map dataDetails() { final data = { - "regNum": controllers["regNum"]?.text, - "insurer": controllers["insurer"]?.text, - "mobile": controllers["mobile"]?.text, - "address": controllers["address"]?.text, - "agent_code": controllers["code"]?.text, - "is_active": isActive, - "manager_id": managerId, + "id": selectedId, + "enquiry_id": widget.id, + "insured_declared_value": controllers["idv"]?.text, + "premium_amount": controllers["premAmount"]?.text, + "insurance_plan_type_id": controllers["insuranceId"]?.text, + "updated_by": userId, }; return data; } @@ -129,42 +130,42 @@ class QuotationTabState extends ConsumerState { }); try { - // if (widget.data != null) { - // final data = List>.from(widget.data as Iterable); - // - // print('quoationListData - ${widget.data}'); - // setState(() { - // getQuotationData = data; - // // getQuotationData = List>.from(response['data']); - // originalData = getQuotationData; - // filteredData = List.from(originalData); - // // print('originalData - $getClaimPolicies'); - // }); - // } + final response; - final response = await apiService.findSingleQuotationData(managerId); + if (widget.data != null && widget.id != null) { + final data = List>.from(widget.data as Iterable); + response = await apiService.findSingleQuotationData(widget.id); + // print('quoationListData - ${widget.data}'); + // setState(() { + // getQuotationData = data; + // // getQuotationData = List>.from(response['data']); + // originalData = getQuotationData; + // filteredData = List.from(originalData); + // // print('originalData - $getClaimPolicies'); + // }); - if (response['status'] == 'success') { - final rawData = response['data']; - print('quoationListData1 - ${response['data']}'); - setState(() { - if (rawData is List) { - // already a list - getQuotationData = List>.from(rawData); - } else if (rawData is Map) { - // single object, wrap into a list - getQuotationData = [Map.from(rawData)]; - } else { - getQuotationData = []; - } - // getQuotationData = List>.from(response['data']); - originalData = getQuotationData; - filteredData = List.from(originalData); - // print('originalData - $getClaimPolicies'); - }); - } else { - getQuotationData = []; - originalData = []; + if (response['status'] == 'success') { + final rawData = response['data']; + print('quoationListData1 - ${response['data']}'); + setState(() { + if (rawData is List) { + // already a list + getQuotationData = List>.from(rawData); + } else if (rawData is Map) { + // single object, wrap into a list + getQuotationData = [Map.from(rawData)]; + } else { + getQuotationData = []; + } + // getQuotationData = List>.from(response['data']); + originalData = getQuotationData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getQuotationData = []; + originalData = []; + } } } catch (e) { print('Exception occurred: $e'); @@ -203,11 +204,33 @@ class QuotationTabState extends ConsumerState { data['insured_declared_value']?.toString() ?? ''; controllers['premAmount']?.text = data['premium_amount']?.toString() ?? ''; - controllers['planType']?.text = + + controllers['insuranceId']?.text = data['insurance_plan_type_id']?.toString() ?? ''; - controllers['addit_doc']?.text = - data['additional_uploaded_file_name']?.toString() ?? ''; + controllers['planType']?.text = + data['insurance_plan_type']?.toString() ?? ''; + controllers['remarks']?.text = data['reject_reason']?.toString() ?? ''; + + String? status = data['status']?.toString() ?? ''; + if (status == 'Pending') { + print('status - $status'); + showAction = true; + } + + String? apiDocPath = data["additional_uploaded_file_name"]; + if (apiDocPath != null && apiDocPath.isNotEmpty) { + print('apiDocPath - $apiDocPath'); + selectedFileNames = apiDocPath.split('/').last; + print('selectedFileNames - $selectedFileNames'); + docUploadedFileFromApi = apiDocPath; + print('docUploadedFileFromApi - $docUploadedFileFromApi'); + docUploadedFile = null; + } else { + selectedFileNames = null; + docUploadedFile = null; + docUploadedFileFromApi = null; + } }); } @@ -266,101 +289,205 @@ class QuotationTabState extends ConsumerState { } } + void UpdataDocuments() { + final dataSet = dataDetails(); + print('UpdataDocuments - $dataSet}'); + createDocumentData(dataSet); + } + + Future createDocumentData(Map userData) async { + final id = widget.id; + final uri = Uri.parse('${Env.apiUrl}quotation/updateQuotation'); + 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'] = + 'nhance-partner-2025-signature-35468846JRhH551HK'; + + print("USerDAta - $userData"); + + // userData.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + + userData.forEach((key, value) { + if (key != 'additional_uploaded_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + } + }); + + // Attach file if selected + if (docUploadedFile != null) { + try { + if (docUploadedFile!.bytes != null) { + final multipartFile = http.MultipartFile.fromBytes( + 'additional_uploaded_file_name', + docUploadedFile!.bytes!, + filename: docUploadedFile!.name, + ); + request.files.add(multipartFile); + } else if (docUploadedFile!.path != null) { + final multipartFile = await http.MultipartFile.fromPath( + 'additional_uploaded_file_name', + docUploadedFile!.path!, + filename: docUploadedFile!.name, + ); + request.files.add(multipartFile); + } + print("📎 File attached: ${docUploadedFile!.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) { + // dispose(); + + ToastHelper.showSuccessToast(context, 'Document Uploaded'); + print("Response: ${response.body}"); + // context.go(AppRoutes.agentLst); + } else { + final responseBody = jsonDecode(response.body); + dynamic msg = responseBody['data']; + print("❌ Submission failed. Status: ${response.statusCode}"); + print("Body: ${response.body}"); + ToastHelper.showErrorToast(context, 'Document Upload Failed'); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } + } + + Color _getStatusColor(String? status) { + switch (status) { + case 'Accepted': + return Colors.green; + case 'Rejected': + return Colors.red; + default: + return Colors.grey; + } + } + @override Widget build(BuildContext context) { + bool isMobile = ResponsiveLayout.isMobile(context); return Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Column( - children: [ - 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: EdgeInsets.all(16.0), + child: filteredData.isNotEmpty + ? SingleChildScrollView( + scrollDirection: Axis.vertical, child: Column( children: [ - // Text('datta') - _buildDataTable(context), - ], - ), - ), - - const SizedBox(height: 20), - if (isquotation) - 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: EdgeInsets.all(26.0), - child: Column( - children: [ - SingleChildScrollView(child: buildFormFields(context)), - - const SizedBox(height: 20), - - Row( - mainAxisAlignment: MainAxisAlignment.end, + 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.all(6.0) + : EdgeInsets.all(16.0), + child: Column( children: [ - GestureDetector( - onTap: () { - handleActions('Rejected'); - }, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 45.0, - vertical: 8, - ), - - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - color: Color(0xFF425B5B), - ), - child: Text( - 'Reject', - style: TextStyle(color: Colors.white), - ), - ), - ), - const SizedBox(width: 10), - GestureDetector( - onTap: () { - handleActions('Accepted'); - }, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 45.0, - vertical: 8, - ), - - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - color: Color(0xFF425B5B), - ), - child: Text( - 'Accept', - style: TextStyle(color: Colors.white), - ), - ), - ), + // Text('datta') + _buildDataTable(context), ], ), - ], - ), + ), + + const SizedBox(height: 20), + if (isquotation) + 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: [ + SingleChildScrollView( + child: buildFormFields(context), + ), + + const SizedBox(height: 20), + + if (showAction) + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + handleActions('Rejected'); + }, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 45.0, + vertical: 8, + ), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text( + 'Reject', + style: TextStyle(color: Colors.white), + ), + ), + ), + const SizedBox(width: 10), + GestureDetector( + onTap: () { + handleActions('Accepted'); + }, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 45.0, + vertical: 8, + ), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text( + 'Accept', + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ), + ], + ), + ), + ], ), - ], - ), - ), + ) + : Center(child: Text('No Available Data')), ); } @@ -531,12 +658,14 @@ class QuotationTabState extends ConsumerState { Widget buildDocuments(BuildContext context) { return buildResponsiveUploadField( - label: "Passport File", + label: 'Quotation Documents', hintText: selectedFileNames, onFileSelected: (fileName, file) { setState(() { docUploadedFile = file; selectedFileNames = fileName; + + UpdataDocuments(); }); }, showDownload: docUploadedFile != null || docUploadedFileFromApi != null, @@ -548,8 +677,8 @@ class QuotationTabState extends ConsumerState { }); }, onDownload: () => apiService.downloadFile( - apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId', - apiId: null, + apiUrl: 'api/quotation/downloadAdditionalUploadedFile?id=$selectedId', + apiId: selectedId, localFile: docUploadedFile, fileName: selectedFileNames, ), @@ -664,14 +793,14 @@ class QuotationTabState extends ConsumerState { 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', - ), + // IconButton( + // onPressed: onRemove, + // icon: const Icon( + // Icons.remove_circle_outline_rounded, + // color: Colors.redAccent, + // ), + // tooltip: 'Remove Upload', + // ), GestureDetector( onTap: onDownload, child: Container( @@ -788,6 +917,7 @@ class QuotationTabState extends ConsumerState { Expanded( flex: 1, child: Checkbox( + activeColor: Colors.black, value: selectedId == item['id'], // only selected row is checked onChanged: (val) { setState(() { @@ -823,10 +953,7 @@ class QuotationTabState extends ConsumerState { ), Expanded( flex: 1, - child: Text( - item['insurance_plan_type_id'] ?? '-', - style: _dataBold, - ), + child: Text(item['insurance_plan_type'] ?? '-', style: _dataBold), ), Expanded( flex: 1, @@ -851,10 +978,11 @@ class QuotationTabState extends ConsumerState { Widget _buildDataCard(Map item, int sno) { return Container( - margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), + // margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: const Color(0xFFF6FEFD), + color: const Color(0xFFFFFFFF), + // color: const Color(0xFFF6FEFD), borderRadius: BorderRadius.circular(8.0), border: Border.all(color: const Color(0xffD9EBE8)), ), @@ -864,6 +992,7 @@ class QuotationTabState extends ConsumerState { children: [ // ✅ Single-select checkbox Checkbox( + activeColor: Colors.black, value: selectedId == item['id'], // only selected row is checked onChanged: (val) { setState(() { @@ -886,56 +1015,69 @@ class QuotationTabState extends ConsumerState { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Company + Vehicle Reg No Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + // flex: 2, + child: Text( + item['insurer_name'] ?? '-', + style: _cardRow1BodyStyle, + ), + ), - mainAxisAlignment: MainAxisAlignment.start, + Expanded( + // flex: 2, + child: Text( + item['insurance_plan_type'] ?? '-', + style: _cardRow1BodyStyle, + ), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + // "TN64V3456", + item['reg_no'] ?? '-', + style: _cardheaderStyle, + ), + Text( + 'IDV: ${item['insured_declared_value']}' ?? '-', + style: _cardRow2BodyStyle, + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + RichText( + text: TextSpan( children: [ - Text( - item['insurer_name'] ?? '-', - - style: _cardBodyStyle, + TextSpan( + text: 'Status : ', // key + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 11, + ), // key color ), - Text( - // "TN64V3456", - item['reg_no'] ?? '-', - - style: _cardheaderStyle, - ), - Text( - 'Status : ${item['status']}' ?? '-', - - style: _cardBodyStyle, + TextSpan( + text: '${item['status'] ?? '-'}', // value + style: TextStyle( + color: _getStatusColor(item['status']), + fontWeight: FontWeight.w600, + fontSize: 11, + ), // value color ), ], ), ), - SizedBox(width: 5), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - item['insurance_plan_type_id'] ?? '-', - style: _cardBodyStyle, - ), - Text( - item['insured_declared_value'] ?? '-', - style: _cardBodyStyle, - ), - Text( - 'Premium Amount - ${item['premium_amount']}' ?? '-', - style: _cardheaderStyle, - ), - ], - ), + + Text( + '${item['premium_amount']}' ?? '-', + style: _cardheaderStyle, ), ], ), @@ -977,8 +1119,21 @@ class QuotationTabState extends ConsumerState { ); static const _cardBodyStyle = TextStyle( + // color: Color(0xFF545454), + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + static const _cardRow1BodyStyle = TextStyle( + // color: Color(0xFF545454), + color: Colors.black, + fontWeight: FontWeight.w500, + fontSize: 12, + ); + static const _cardRow2BodyStyle = TextStyle( color: Color(0xFF545454), - fontWeight: FontWeight.w400, + // color: Colors.black, + fontWeight: FontWeight.w500, fontSize: 12, ); } diff --git a/lib/presentation/screens/Enquiry/enquiry/tabs.dart b/lib/presentation/screens/Enquiry/enquiry/tabs.dart index 0def356..a7c1ac2 100644 --- a/lib/presentation/screens/Enquiry/enquiry/tabs.dart +++ b/lib/presentation/screens/Enquiry/enquiry/tabs.dart @@ -19,12 +19,13 @@ class TabEnquiryList extends ConsumerStatefulWidget { } class TabEnquiryListState extends ConsumerState { + int? expandedIndex; int selectedIndex = 0; List tabs = []; Map? enquiryData; bool isLoading = true; late ApiService apiService; - + ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); @@ -76,6 +77,7 @@ class TabEnquiryListState extends ConsumerState { data: (enquiryData?["policies"] as List?)! .map((e) => Map.from(e as Map)) .toList(), + id: id ?? "", ), ), @@ -103,6 +105,7 @@ class TabEnquiryListState extends ConsumerState { return MainLayout( title: "Enquiry", + body: SafeArea( child: isLoading ? const Center(child: CircularProgressIndicator()) @@ -118,22 +121,55 @@ class TabEnquiryListState extends ConsumerState { itemCount: tabs.length, padding: const EdgeInsets.all(16), itemBuilder: (context, index) { + final isExpanded = expandedIndex == index; + return Card( margin: const EdgeInsets.only(bottom: 12), - color: const Color(0xFF425B5B), + color: isExpanded ? const Color(0xFFEDF6F5) : const Color(0xFF425B5B), + // color: Color(0xFFEDF6F5), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: isExpanded ? Color(0xFF425B5B) : Color(0xFF425B5B), + // color: isExpanded ? Color(0xFFEDF6F5) : Color(0xFFEDF6F5), + width: 1, + ), + ), child: ExpansionTile( - collapsedIconColor: Colors.white, - iconColor: Colors.white, + collapsedIconColor: isExpanded ? Colors.black : Colors.white, + iconColor: isExpanded ? Colors.black : Colors.white, + initiallyExpanded: isExpanded, + onExpansionChanged: (expanded) { + setState(() { + if (expanded) { + expandedIndex = index; + // Scroll to make the expanded tile visible + WidgetsBinding.instance.addPostFrameCallback((_) { + RenderBox box = context.findRenderObject() as RenderBox; + double yPos = box.localToGlobal(Offset.zero).dy; + _scrollController.animateTo( + _scrollController.offset + + yPos - + 100, // adjust 100 if needed + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }); + } else { + expandedIndex = null; + } + }); + }, title: Text( tabs[index].title, style: GoogleFonts.inter( - color: Colors.white, + color: isExpanded ? Colors.black : Colors.white, fontWeight: FontWeight.w600, ), ), children: [ Container( - padding: const EdgeInsets.all(12), + // padding: const EdgeInsets.all(12), child: tabs[index].widget, ), ], @@ -150,7 +186,9 @@ class TabEnquiryListState extends ConsumerState { padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), child: GestureDetector( onTap: () { - context.go(AppRoutes.dashboard); + // context.go(AppRoutes.dashboard); + ref.read(enquiryIdProvider.notifier).state = null; + context.go(AppRoutes.enquiryLst); }, child: Row( children: [ @@ -213,424 +251,3 @@ class TabItem { final Widget widget; TabItem(this.title, this.widget); } - -// class TabEnquiryListState extends ConsumerState { -// int selectedIndex = 0; // 0 = Enquiry, 1 = Quotation, 2 = Policy -// -// // final List tabs = ["Enquiry", "Quotation", "Policy"]; -// // final List tabWidgets = [EnquiryTab(), QuotationTab(), PolicyTab()]; -// // late List tabWidgets; -// -// late List> tabs; -// -// Map? enquiryData; -// bool isLoading = true; -// late ApiService apiService; -// -// @override -// void initState() { -// super.initState(); -// apiService = ApiService(); -// _loadData(); -// } -// -// Future _loadData() async { -// final id = ref.read(enquiryIdProvider); -// if (id != null && id.isNotEmpty) { -// setState(() => isLoading = true); -// final response = await apiService.findEnqQuotePolicyView(id); -// setState(() { -// enquiryData = response["data"]; -// isLoading = false; -// tabs = [ -// TabItem("Enquiry", EnquiryTab(data: enquiryData?["enquiry"])), -// TabItem("Quotation", QuotationTab(id: id)), -// TabItem("Policy", PolicyTab()), -// ]; -// }); -// } else { -// setState(() { -// isLoading = false; -// tabs = [ -// TabItem("Enquiry", EnquiryTab()), -// TabItem("Quotation", QuotationTab(id: "")), -// TabItem("Policy", PolicyTab()), -// ]; -// }); -// } -// } -// -// // Future _fetchData() async { -// // final id = ref.read(enquiryIdProvider); -// // if (id != null && id.isNotEmpty) { -// // setState(() { -// // isLoading = true; -// // }); -// // -// // final response = await apiService.findEnqQuotePolicyView(id); -// // -// // setState(() { -// // enquiryData = response["data"]; -// // tabs = [ -// // TabItem("Enquiry", EnquiryTab(data: enquiryData?["enquiry"])), -// // TabItem("Quotation", QuotationTab(id: id)), -// // TabItem("Policy", PolicyTab()), -// // ]; -// // isLoading = false; -// // }); -// // } else { -// // setState(() { -// // tabs = [ -// // TabItem("Enquiry", EnquiryTab()), -// // TabItem("Quotation", QuotationTab(id: "")), -// // TabItem("Policy", PolicyTab()), -// // ]; -// // isLoading = false; -// // }); -// // } -// // } -// -// // Future _fetchData() async { -// // final id = ref.read(enquiryIdProvider); -// // if (id != null && id.isNotEmpty) { -// // final response = await apiService.findEnqQuotePolicyView(id); -// // setState(() { -// // enquiryData = response["data"]; -// // isLoading = false; -// // }); -// // } -// // } -// -// // @override -// // Widget build(BuildContext context) { -// // final bool isMobile = MediaQuery.of(context).size.width < 600; -// // final id = ref.watch(enquiryIdProvider); // listen to provider -// // -// // print('ENQID: $id'); -// // // final tabs = [ -// // // TabItem("Enquiry", EnquiryTab(id: id ?? "")), -// // // TabItem("Quotation", QuotationTab(id: id ?? "")), -// // // TabItem("Policy", PolicyTab()), -// // // ]; -// // final tabs; -// // if (id != null) { -// // print('HASENQID: $id'); -// // setState(() { -// // isLoading = true; -// // }); -// // -// // _fetchData(); -// // -// // setState(() { -// // isLoading = false; -// // }); -// // -// // tabs = [ -// // TabItem("Enquiry", EnquiryTab(data: enquiryData?["enquiry"])), -// // -// // // TabItem("Quotation", QuotationTab(data: enquiryData?["quotations"])), -// // // TabItem("Policy", PolicyTab(data: enquiryData?["policies"])), -// // TabItem("Quotation", QuotationTab(id: id ?? "")), -// // TabItem("Policy", PolicyTab()), -// // ]; -// // } else { -// // setState(() { -// // isLoading = false; -// // }); -// // -// // print('HASENQIDNot'); -// // tabs = [ -// // TabItem("Enquiry", EnquiryTab()), -// // -// // // TabItem("Quotation", QuotationTab(data: enquiryData?["quotations"])), -// // // TabItem("Policy", PolicyTab(data: enquiryData?["policies"])), -// // TabItem("Quotation", QuotationTab(id: id ?? "")), -// // TabItem("Policy", PolicyTab()), -// // ]; -// // } -// // -// // return MainLayout( -// // title: "Enquiry", -// // body: SafeArea( -// // child: isLoading -// // ? const Center( -// // child: CircularProgressIndicator(), // 👈 loader inside SafeArea -// // ) -// // : isMobile -// // ? ListView.builder( -// // itemCount: tabs.length, -// // padding: const EdgeInsets.all(16), -// // itemBuilder: (context, index) { -// // return Card( -// // shape: RoundedRectangleBorder( -// // borderRadius: BorderRadius.circular(8), -// // ), -// // margin: const EdgeInsets.only(bottom: 12), -// // color: const Color(0xFF425B5B), // Header background -// // child: Theme( -// // data: Theme.of(context).copyWith( -// // dividerColor: -// // Colors.transparent, // remove default divider -// // ), -// // child: ExpansionTile( -// // collapsedIconColor: Colors.white, -// // iconColor: Colors.white, -// // title: Text( -// // // tabs[index]["title"], -// // tabs[index].title, -// // style: GoogleFonts.inter( -// // color: Colors.white, -// // fontWeight: FontWeight.w600, -// // ), -// // ), -// // children: [ -// // Container( -// // width: double.infinity, -// // decoration: BoxDecoration( -// // color: const Color(0xFFEAF6F4), -// // borderRadius: BorderRadius.circular(8), -// // border: Border.all( -// // color: const Color(0xFFB0CFCB), -// // width: 1, -// // ), -// // ), -// // padding: const EdgeInsets.all(12), -// // child: SizedBox( -// // height: MediaQuery.of(context).size.height, -// // child: tabs[selectedIndex].widget, -// // // child: tabs[index]["widget"] as Widget, -// // ), // ✅ directly, no SizedBox height -// // ), -// // // Container( -// // // width: double.infinity, -// // // -// // // decoration: BoxDecoration( -// // // color: const Color(0xFFEAF6F4), // light teal bg like screenshot -// // // borderRadius: BorderRadius.circular(8), -// // // border: Border.all( -// // // color: const Color(0xFFB0CFCB), // soft border color -// // // width: 1, -// // // ), -// // // ), -// // // padding: const EdgeInsets.all(12), -// // // child: SizedBox( -// // // height: MediaQuery.of(context).size.height, -// // // // mainAxisSize: MainAxisSize.min, // 👈 prevents collapse -// // // // children: [ -// // // child: tabs[index]["widget"] as Widget, // ✅ actual tab widget -// // // // ], -// // // ), -// // // ), -// // ], -// // ), -// // ), -// // ); -// // }, -// // ) -// // : Column( -// // crossAxisAlignment: CrossAxisAlignment.start, -// // children: [ -// // // Back Button + Title -// // Padding( -// // padding: const EdgeInsets.symmetric( -// // horizontal: 6, -// // vertical: 2, -// // ), -// // child: GestureDetector( -// // onTap: () { -// // context.go(AppRoutes.dashboard); -// // }, -// // child: Row( -// // children: [ -// // const Icon( -// // Icons.arrow_left_sharp, -// // size: 35, -// // color: Color(0xFF425B5B), -// // ), -// // const SizedBox(width: 8), -// // Text( -// // "Enquiry", -// // style: GoogleFonts.inter( -// // fontSize: 18, -// // fontWeight: FontWeight.w700, -// // color: Colors.black87, -// // ), -// // ), -// // ], -// // ), -// // ), -// // ), -// // -// // const SizedBox(height: 10), -// // -// // // Tabs -// // Padding( -// // padding: const EdgeInsets.symmetric(horizontal: 16), -// // child: Row( -// // children: List.generate(tabs.length, (index) { -// // final bool isSelected = selectedIndex == index; -// // return Padding( -// // padding: const EdgeInsets.only(right: 12), -// // child: ElevatedButton( -// // style: ElevatedButton.styleFrom( -// // elevation: 2, -// // backgroundColor: isSelected -// // ? const Color(0xFF425B5B) -// // : const Color(0xFFEDFFFC), -// // foregroundColor: isSelected -// // ? Colors.white -// // : Colors.black87, -// // shape: RoundedRectangleBorder( -// // borderRadius: BorderRadius.circular(6), -// // ), -// // padding: const EdgeInsets.symmetric( -// // horizontal: 24, -// // vertical: 12, -// // ), -// // ), -// // onPressed: () { -// // setState(() { -// // selectedIndex = index; -// // }); -// // }, -// // child: Text( -// // // tabs[index]["title"], -// // tabs[index].title, -// // style: GoogleFonts.inter( -// // fontWeight: isSelected -// // ? FontWeight.w600 -// // : FontWeight.w500, -// // fontSize: 15, -// // ), -// // ), -// // ), -// // ); -// // }), -// // ), -// // ), -// // -// // const SizedBox(height: 16), -// // -// // // Tab Content -// // Expanded( -// // child: Padding( -// // padding: const EdgeInsets.symmetric(horizontal: 16), -// // child: tabs[selectedIndex].widget, -// // // child: tabs[selectedIndex]["widget"], -// // ), -// // ), -// // ], -// // ), -// // ), -// // ); -// // } -// -// // Widget build(BuildContext context) { -// // return MainLayout( -// // title: "Enquiry", -// // body: SafeArea( -// // child: Column( -// // crossAxisAlignment: CrossAxisAlignment.start, -// // mainAxisAlignment: MainAxisAlignment.start, -// // children: [ -// // // Header -// // Padding( -// // padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), -// // child: GestureDetector( -// // onTap: () { -// // context.go(AppRoutes.dashboard); -// // }, -// // child: Row( -// // children: [ -// // const Icon( -// // Icons.arrow_left_sharp, -// // size: 35, -// // color: Color(0xFF425B5B), -// // ), -// // const SizedBox(width: 8), -// // Text( -// // "Enquiry", -// // style: GoogleFonts.inter( -// // fontSize: 18, -// // fontWeight: FontWeight.w700, -// // color: Colors.black87, -// // ), -// // ), -// // ], -// // ), -// // ), -// // ), -// // -// // const SizedBox(height: 10), -// // -// // // Tab Buttons -// // Padding( -// // padding: const EdgeInsets.symmetric(horizontal: 16), -// // child: Row( -// // children: List.generate(tabs.length, (index) { -// // final bool isSelected = selectedIndex == index; -// // return Padding( -// // padding: const EdgeInsets.only(right: 12), -// // child: ElevatedButton( -// // style: ElevatedButton.styleFrom( -// // elevation: 2, -// // backgroundColor: isSelected -// // ? const Color(0xFF425B5B) // selected dark green -// // : const Color(0xFFEDFFFC), // light teal -// // foregroundColor: isSelected -// // ? Colors.white -// // : Colors.black87, -// // side: BorderSide( -// // color: isSelected -// // ? const Color(0xFF425B5B) -// // : const Color(0xFFEDFFFC), -// // ), -// // shape: RoundedRectangleBorder( -// // borderRadius: BorderRadius.circular(6), -// // ), -// // padding: const EdgeInsets.symmetric( -// // horizontal: 24, -// // vertical: 12, -// // ), -// // ), -// // onPressed: () { -// // setState(() { -// // selectedIndex = index; -// // }); -// // }, -// // child: Text( -// // tabs[index], -// // style: GoogleFonts.inter( -// // fontWeight: isSelected -// // ? FontWeight.w600 -// // : FontWeight.w500, -// // fontSize: 15, -// // ), -// // ), -// // ), -// // ); -// // }), -// // ), -// // ), -// // -// // const SizedBox(height: 16), -// // -// // // Tab content -// // Expanded( -// // child: Padding( -// // padding: const EdgeInsets.symmetric(horizontal: 16), -// // child: tabWidgets[selectedIndex], -// // ), -// // ), -// // ], -// // ), -// // ), -// // ); -// // } -// } - -// class TabItem { -// final String title; -// final Widget widget; -// TabItem(this.title, this.widget); -// } diff --git a/lib/presentation/screens/Enquiry/enquiryList.dart b/lib/presentation/screens/Enquiry/enquiryList.dart index 89194c5..2e4038d 100644 --- a/lib/presentation/screens/Enquiry/enquiryList.dart +++ b/lib/presentation/screens/Enquiry/enquiryList.dart @@ -249,6 +249,8 @@ class EnquiryListState extends ConsumerState { SizedBox(width: 10), GestureDetector( onTap: () { + ref.read(enquiryIdProvider.notifier).state = null; + context.go(AppRoutes.tabEnquiry); // print('Export'); }, child: Container( @@ -264,21 +266,33 @@ class EnquiryListState extends ConsumerState { if (!ResponsiveLayout.isMobile(context)) ...[ SizedBox(width: 10), - - GestureDetector( - onTap: () { - // context.go(AppRoutes.agent / create); - context.go('/tabEnquiry/tab'); - }, - child: Text( - 'Create New Enquiry', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14, - ), + Text( + 'Create New Enquiry', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 14, ), ), + // GestureDetector( + // onTap: () { + // ref + // .read( + // enquiryIdProvider.notifier, + // ) + // .state = + // null; + // context.go(AppRoutes.tabEnquiry); + // }, + // child: Text( + // 'Create New Enquiry', + // style: TextStyle( + // color: Colors.white, + // fontWeight: FontWeight.w600, + // fontSize: 14, + // ), + // ), + // ), ], ], ), @@ -288,51 +302,53 @@ class EnquiryListState extends ConsumerState { ), ), SizedBox(height: 10), - Container( - decoration: BoxDecoration( - color: Color(0xFFEDF6F5), - borderRadius: BorderRadius.circular(6), - ), - padding: const EdgeInsets.symmetric( - vertical: 12, - horizontal: 16, - ), - child: const Row( - children: [ - Expanded( - flex: 1, - child: Text('S.No.', style: _headerStyle), - ), - Expanded( - flex: 2, - child: Text( - 'Received Date & Time', - style: _headerStyle, + + if (!ResponsiveLayout.isMobile(context)) + Container( + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: const Row( + children: [ + Expanded( + flex: 1, + child: Text('S.No.', style: _headerStyle), ), - ), - Expanded( - flex: 1, - child: Text('Reg.No.', style: _headerStyle), - ), - Expanded( - flex: 2, - child: Text('Company', style: _headerStyle), - ), - Expanded( - flex: 2, - child: Text('Status', style: _headerStyle), - ), - Expanded( - flex: 1, - child: Text('Remarks', style: _headerStyle), - ), - Expanded( - flex: 1, - child: Text('Action', style: _headerStyle), - ), - ], + Expanded( + flex: 2, + child: Text( + 'Received Date & Time', + style: _headerStyle, + ), + ), + Expanded( + flex: 1, + child: Text('Reg.No.', style: _headerStyle), + ), + Expanded( + flex: 3, + child: Text('Company', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Status', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Remarks', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Action', style: _headerStyle), + ), + ], + ), ), - ), Expanded(child: _buildDataTable(context)), ], ), @@ -430,7 +446,7 @@ class EnquiryListState extends ConsumerState { child: Text(item['reg_no'] ?? '-', style: _dataBold), ), Expanded( - flex: 2, + flex: 3, child: Text( item['insurer_name'] ?? '-', style: _dataBold, diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/claimsHistory.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/claimsHistory.dart new file mode 100644 index 0000000..4538191 --- /dev/null +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/claimsHistory.dart @@ -0,0 +1,701 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; +import '../../../../core/routing/routes.dart'; +import '../../../../core/services/api_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../themes/indicators/export_btn.dart'; +import '../../../themes/indicators/search_field_theme.dart'; +import '../../../widgets/custom_action_popup.dart'; + +// class claimList extends ConsumerStatefulWidget { +// const claimList({super.key}); +// @override +// ConsumerState createState() => claimListState(); +// } +// +// class claimListState extends ConsumerState { +// late ApiService apiService; +// List> getClaimsHistoryList = []; +// List stepKeys = []; +// late Map stepMap; +// int _index = 4; +// bool isLoading = false; +// +// @override +// void initState() { +// super.initState(); +// +// apiService = ApiService(); +// // print(widget.postToken); +// print("CLAIMHISTORY"); +// print(widget.claimAmount); +// print(widget.claimNo); +// print(widget.clientPolicyNo); +// print(widget.empCode); +// print(widget.policyType); +// print(widget.ticket_id); +// getClaimsHistoryDetails(); +// } +// +// @override +// void dispose() { +// super.dispose(); +// } +// +// Future getClaimsHistoryDetails() async { +// setState(() { +// isLoading = true; +// }); +// try { +// print('10'); +// // final ticketID = widget.ticket_id; +// // if (ticketID != '' || ticketID != null) { +// // return; +// // } +// final response = await apiService.getClaimsHistoryToApi(widget.ticket_id); +// if (response['status'] == 'success') { +// setState(() { +// isLoading = false; +// print('Claims History List1'); +// // final List ticketDataList = response['data']['ticket_data']; +// // final Map ticketDataMap = +// // response['data']['ticket_data']; +// // print('Claims History List12'); +// // print('Claims History List1- $ticketDataMap'); +// +// // getClaimsHistoryList = ticketDataList +// // .map((item) => Map.from(item)) +// // .toList(); +// +// // getClaimsHistoryList = ticketDataMap.entries.map((entry) { +// // return { +// // 'status': entry.key, +// // ...Map.from(entry.value), +// // }; +// // }).toList(); +// // +// // getClaimsHistoryList = ticketDataMap.entries.map((entry) { +// // return { +// // 'status': entry.key, +// // ...Map.from(entry.value), +// // }; +// // }).toList(); +// +// // if (getClaimsHistoryList.isNotEmpty) { +// // stepMap = getClaimsHistoryList[0]; +// // stepKeys = stepMap.keys.toList(); +// // } +// +// print('Claims History List: $getClaimsHistoryList'); +// +// getClaimsHistoryList = [ +// Map.from(response['data']['ticket_data']), +// ]; +// stepMap = getClaimsHistoryList[0]; +// stepKeys = stepMap.keys.toList(); +// +// // originalData = getCDPolicies; +// // filteredData = List.from(originalData); +// // print('filteredData'); +// // print(filteredData); +// }); +// } else { +// setState(() { +// isLoading = false; +// }); +// +// // ToastHelper.showWarningToast( +// // context, 'Request failed with status: ${response.statusCode}'); +// print('Request failed with status: ${response['code']}'); +// } +// } catch (e) { +// setState(() { +// isLoading = false; +// }); +// print('Exception occurred: $e'); +// } finally { +// setState(() { +// // _isLoading = false; +// }); +// } +// } +// +// @override +// Widget build(BuildContext context) { +// // if (getClaimsHistoryList.isEmpty) { +// // return SizedBox( +// // height: 50, +// // child: Center(child: Text('No available Claims')), +// // ); +// // } +// final keyValueWidgets = [ +// _buildKeyValue( +// 'Name', +// '${widget.empName ?? ''} (${widget.empCode ?? ''})', +// ), +// SizedBox( +// width: Responsive.isDesktop(context) ? 16 : 0, +// height: Responsive.isDesktop(context) ? 0 : 8, +// ), +// _buildKeyValue( +// 'Policy Name', +// '${widget.policyType ?? ''} - ${widget.clientPolicyNo ?? ''}', +// ), +// ]; +// +// final keyValueWidgetRow = [ +// _buildKeyValue( +// 'Claim Amount', +// widget.claimAmount == null || widget.claimAmount!.trim().isEmpty +// ? 'N/A' +// : '₹${widget.claimAmount}', +// ), +// SizedBox( +// width: Responsive.isDesktop(context) ? 16 : 0, +// height: Responsive.isDesktop(context) ? 0 : 8, +// ), +// _buildKeyValue( +// 'Claim Number', +// widget.claimNo == null || widget.claimNo!.trim().isEmpty +// ? 'N/A' +// : widget.claimNo!, +// ), +// ]; +// +// return Container( +// constraints: BoxConstraints(maxWidth: 800, maxHeight: 800), +// padding: EdgeInsets.all(20), +// decoration: BoxDecoration( +// color: Colors.white, +// borderRadius: BorderRadius.circular(12), +// ), +// child: SingleChildScrollView( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Row( +// children: [ +// Expanded( +// child: Align( +// alignment: Alignment.centerLeft, +// child: Text( +// 'Claim History', +// style: GoogleFonts.poppins( +// fontSize: Responsive.isDesktop(context) ? 20 : 16, +// fontWeight: FontWeight.w500, +// color: Color(0xFF101010), +// ), +// ), +// ), +// ), +// MouseRegion( +// cursor: SystemMouseCursors.click, // Show pointer cursor +// child: GestureDetector( +// onTap: () => Navigator.of(context).pop(), +// child: Container( +// height: 30, +// width: 30, +// decoration: BoxDecoration( +// color: Colors.white, +// border: Border.all(color: Color(0xFFBCBCBC)), +// borderRadius: BorderRadius.circular(6), +// ), +// child: Icon( +// Icons.close, +// size: 25, +// color: Color(0xFFBCBCBC), +// ), +// ), +// ), +// ), +// ], +// ), +// SizedBox(height: Responsive.isDesktop(context) ? 10 : 5), +// Container( +// margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 20), +// decoration: BoxDecoration( +// color: Color(0xFFFFFFFF), // White background +// borderRadius: BorderRadius.circular(12), +// boxShadow: [ +// BoxShadow( +// color: Color(0xFFEBEBEB), // Shadow color +// blurRadius: 14, // How soft the shadow is +// spreadRadius: 2, // How much it spreads +// offset: Offset(0, 1), // X and Y offset +// ), +// ], +// ), +// padding: const EdgeInsets.all(16), +// child: Center( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Responsive.isDesktop(context) +// ? Row( +// children: keyValueWidgets +// .map((w) => Expanded(child: w)) +// .toList(), +// ) +// : Container( +// width: MediaQuery.of(context).size.width, +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: keyValueWidgets, +// ), +// ), +// // Row( +// // children: [ +// // Expanded( +// // child: _buildKeyValue('Name', +// // '${widget.empName ?? ''} (${widget.empCode ?? ''})'), +// // ), +// // SizedBox(width: 16), +// // Expanded( +// // child: _buildKeyValue('Policy Name', +// // '${widget.policyType ?? ''} - ${widget.clientPolicyNo ?? ''}')), +// // ], +// // ), +// SizedBox(height: Responsive.isDesktop(context) ? 16 : 8), +// Responsive.isDesktop(context) +// ? Row( +// children: keyValueWidgetRow +// .map((w) => Expanded(child: w)) +// .toList(), +// ) +// : Container( +// width: MediaQuery.of(context).size.width, +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: keyValueWidgetRow, +// ), +// ), +// ], +// ), +// ), +// ), +// SizedBox(height: 10), +// +// // Container( +// // padding: const EdgeInsets.all(16), +// // child: Stepper( +// // currentStep: _index, +// // onStepCancel: () { +// // if (_index > 0) { +// // setState(() { +// // _index -= 1; +// // }); +// // } +// // }, +// // onStepContinue: () { +// // if (_index < 4) { +// // setState(() { +// // _index += 1; +// // }); +// // } +// // }, +// // onStepTapped: (int index) { +// // setState(() { +// // _index = index; +// // }); +// // }, +// // steps: [ +// // Step( +// // title: Text('Step 1: PAYMENT INITIATED'), +// // content: Text('Pay Initiate Date: 05-05-2025'), +// // isActive: true, +// // state: StepState.complete, +// // ), +// // Step( +// // title: Text('Step 2: INFORMATION REQUIRED'), +// // content: Text('Raised Date: 05-05-2025'), +// // isActive: true, +// // state: StepState.complete, +// // ), +// // Step( +// // title: Text('Step 3: CLAIM NO. UPDATION'), +// // content: Column( +// // crossAxisAlignment: CrossAxisAlignment.start, +// // children: [ +// // Text('Claim Number: 4315440'), +// // Text('Registration Date: 05-05-2025'), +// // ], +// // ), +// // isActive: true, +// // state: StepState.complete, +// // ), +// // Step( +// // title: Text('Step 4: QUERY DOCUMENT REQUIRED'), +// // content: Text('Query Received Date: 05-05-2025'), +// // isActive: true, +// // state: StepState.complete, +// // ), +// // Step( +// // title: Text('Step 5: APPROVED'), +// // content: Column( +// // crossAxisAlignment: CrossAxisAlignment.start, +// // children: [ +// // Text('Approved Amount: 4315440'), +// // Text('Approved Date: 05-05-2025'), +// // Text('Approved Letter: Lorem ipsum...'), +// // Text('Description: Lorem ipsum...'), +// // ], +// // ), +// // isActive: true, +// // state: StepState.complete, +// // ), +// // ], +// // ), +// // ) +// // Column( +// // crossAxisAlignment: CrossAxisAlignment.start, +// // children: List.generate(5, (index) { +// // return _buildStep( +// // stepNumber: index + 1, +// // title: _getStepTitle(index), +// // content: _getStepContent(index), +// // isLast: index == 4, +// // ); +// // }), +// // ) +// isLoading +// ? Container( +// // color: Color(0x98FFFCE5), // Semi-transparent background +// child: Center( +// child: // Your GIF loader widget +// Image.asset( +// height: 60, +// width: 60, +// 'assets/nhance-loader.gif', +// ), // Adjust path to your GIF loader +// ), +// ) +// : Container( +// child: getClaimsHistoryList.isNotEmpty +// ? Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: List.generate(stepKeys.length, (index) { +// String stepTitleKey = stepKeys[index]; +// Map stepData = +// stepMap[stepTitleKey]; +// +// print('stepTitleKey'); +// print(stepTitleKey); +// print('stepData'); +// print(stepData); +// +// Widget content = _getStepContentFromApi(stepData); +// +// return _buildStep( +// stepNumber: index + 1, +// title: _getStepTitleFromApi( +// stepTitleKey, +// stepData, +// ), +// content: content, +// // content: _getStepContentFromApi(stepData), +// isLast: index == stepKeys.length - 1, +// ); +// }), +// ) +// : Container( +// height: MediaQuery.of(context).size.height * 0.4, +// // color: Colors.red, +// child: Center( +// child: Column( +// children: [ +// Image.asset( +// 'assets/searchData.jpg', // Replace 'default_image.png' with your default image asset path +// width: 200, +// height: 200, +// fit: BoxFit.cover, +// ), +// Text( +// 'No Claim History', +// style: TextStyle( +// fontWeight: FontWeight.w500, +// fontSize: 15, +// ), +// ), +// ], +// ), +// ), +// ), +// ), +// ], +// ), +// ), +// ); +// } +// +// Widget _buildStep({ +// required int stepNumber, +// // required String title, +// required Widget title, +// required Widget content, +// bool isLast = false, +// }) { +// print(title); +// final noContent; +// if ((content as Column).children.isEmpty) { +// noContent = 0; +// } else { +// noContent = 1; +// } +// +// return Row( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// // Left Column with circle + line +// Column( +// children: [ +// // Add top spacing before circle +// SizedBox(height: stepNumber == 1 ? 0 : 4), +// +// // Step number circle +// Container( +// height: 28, +// width: 28, +// decoration: BoxDecoration( +// color: Color(0xFF00A5A8), +// shape: BoxShape.circle, +// ), +// alignment: Alignment.center, +// child: Text( +// '$stepNumber', +// style: TextStyle( +// color: Colors.white, +// fontSize: Responsive.isDesktop(context) ? 13 : 12, +// fontWeight: FontWeight.w600, +// ), +// ), +// ), +// +// // Dotted line below circle (except for last step) +// if (!isLast) +// Container( +// height: noContent == 1 ? 50 : 20, +// // increase to extend line +// width: 2, +// margin: EdgeInsets.only(top: 4, bottom: 4), +// child: CustomPaint(painter: DottedLinePainter()), +// ), +// ], +// ), +// +// SizedBox(width: 12), +// +// // Right Side: Step title and content +// Expanded( +// child: Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// title, +// if (noContent == 1) SizedBox(height: noContent == 0 ? 0 : 8), +// if (noContent == 1) +// Container( +// width: double.infinity, +// padding: EdgeInsets.all(12), +// decoration: BoxDecoration( +// color: Color(0xFFF7F7F7), +// borderRadius: BorderRadius.circular(8), +// border: Border.all(color: Color(0xFFE0E0E0)), +// ), +// child: content, +// ), +// if (noContent == 1) SizedBox(height: isLast ? 0 : 16), +// ], +// ), +// ), +// ], +// ); +// } +// +// // String _getStepTitleFromApi(String status, Map data) { +// // final modifiedBy = data['modified_by'] ?? ''; +// // final modifiedAt = data['modified_at'] ?? ''; +// // return '$status ($modifiedBy – $modifiedAt)'; +// // } +// +// Widget _getStepTitleFromApi(String status, Map data) { +// final modifiedBy = data['modified_by'] ?? ''; +// final modifiedAt = data['modified_at'] ?? ''; +// final isDesktop = Responsive.isDesktop(context); +// +// return RichText( +// text: TextSpan( +// children: [ +// TextSpan( +// text: status + (isDesktop ? ' ' : '\n'), +// style: GoogleFonts.poppins( +// fontSize: Responsive.isDesktop(context) ? 15 : 11, +// fontWeight: FontWeight.w500, +// color: Color(0xFF212120), // Status color +// ), +// ), +// TextSpan( +// text: ' ($modifiedBy – $modifiedAt)', +// style: GoogleFonts.poppins( +// fontSize: Responsive.isDesktop(context) ? 14 : 11, +// fontWeight: FontWeight.w400, +// color: Color(0xFF565656), // Subtitle color +// ), +// ), +// ], +// ), +// ); +// } +// +// Widget _getStepContentFromApi(Map data) { +// List rows = []; +// +// data.forEach((key, value) { +// // Skip metadata fields +// if (key == 'modified_by' || key == 'modified_at') return; +// +// String displayName = value['display_name'] ?? key; +// String displayValue = value['display_value'] ?? 'N/A'; +// +// rows.add(_buildHistoryListData(displayName, displayValue)); +// rows.add(SizedBox(height: 1)); +// }); +// +// return Column(crossAxisAlignment: CrossAxisAlignment.start, children: rows); +// } +// +// Widget _buildKeyValue(String title, String value) { +// final displayValue = (value == null || value.trim().isEmpty) +// ? 'N/A' +// : value; +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Text( +// title, +// style: GoogleFonts.poppins( +// color: Color(0xFF747474), +// fontWeight: FontWeight.w400, +// fontSize: Responsive.isDesktop(context) ? 16 : 13, +// ), +// ), +// SizedBox(height: 4), +// Text( +// displayValue, +// style: GoogleFonts.poppins( +// color: Color(0xFF000000), +// fontWeight: FontWeight.w500, +// fontSize: Responsive.isDesktop(context) ? 16 : 13, +// ), +// ), +// ], +// ); +// } +// +// Widget _buildHistoryListData(String title, String value) { +// final displayValue = (value == null || value.trim().isEmpty) +// ? 'N/A' +// : value; +// +// final titleText = Text( +// title, +// style: GoogleFonts.poppins( +// color: const Color(0xFF747474), +// fontWeight: FontWeight.w400, +// fontSize: Responsive.isDesktop(context) ? 14 : 12, +// ), +// ); +// +// final valueText = Text( +// displayValue, +// style: GoogleFonts.poppins( +// color: const Color(0xFF000000), +// fontWeight: FontWeight.w400, +// fontSize: Responsive.isDesktop(context) ? 14 : 12, +// ), +// textAlign: TextAlign.right, +// ); +// +// return Padding( +// padding: const EdgeInsets.symmetric(vertical: 1), // optional spacing +// child: Responsive.isDesktop(context) +// ? Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// crossAxisAlignment: CrossAxisAlignment.center, +// children: [ +// Expanded( +// child: Align( +// alignment: Alignment.centerLeft, +// child: titleText, +// ), +// ), +// Expanded( +// child: Align( +// alignment: Alignment.centerRight, +// child: valueText, +// ), +// ), +// +// // Title - Align to center left +// // Expanded( +// // child: Align( +// // alignment: Alignment.centerLeft, +// // child: Text( +// // title, +// // style: GoogleFonts.poppins( +// // color: const Color(0xFF747474), +// // fontWeight: FontWeight.w400, +// // fontSize: 14, +// // ), +// // ), +// // ), +// // ), +// +// // Value - Align to center right +// // Expanded( +// // child: Align( +// // alignment: Alignment.centerRight, +// // child: Text( +// // displayValue, +// // style: GoogleFonts.poppins( +// // color: const Color(0xFF000000), +// // fontWeight: FontWeight.w400, +// // fontSize: 14, +// // ), +// // ), +// // ), +// // ), +// ], +// ) +// : Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [titleText, SizedBox(height: 4), valueText], +// ), +// ); +// } +// } +// +// class DottedLinePainter extends CustomPainter { +// @override +// void paint(Canvas canvas, Size size) { +// const dashHeight = 2.0; +// const dashSpace = 3.0; +// double startY = 0; +// final paint = Paint() +// ..color = Colors.grey.shade400 +// ..strokeWidth = 1; +// +// while (startY < size.height) { +// canvas.drawLine(Offset(0, startY), Offset(0, startY + dashHeight), paint); +// startY += dashHeight + dashSpace; +// } +// } +// +// @override +// bool shouldRepaint(CustomPainter oldDelegate) => false; +// } diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/sub_claims.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/sub_claims.dart new file mode 100644 index 0000000..a5bc469 --- /dev/null +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/sub_claims.dart @@ -0,0 +1,431 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:http/http.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; +import '../../../../core/routing/routes.dart'; +import '../../../../core/services/api_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../widgets/custom_action_popup.dart'; + +class ClaimsSubList extends ConsumerStatefulWidget { + final dynamic policyNumber; + ClaimsSubList({super.key, this.policyNumber}); + @override + ConsumerState createState() => ClaimsSubListState(); +} + +class ClaimsSubListState extends ConsumerState { + int currentPage = 1; + int itemsPerPage = 10; + late ApiService apiService; + + // List> dataVal = []; + List> getStaffData = []; + List> originalData = []; + List> filteredData = []; + bool isLoading = false; + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + + if (widget.policyNumber != null) { + getClaimsList(widget.policyNumber); + } + // Future.microtask(() { + // // final id = ref.read(managerIdProvider); + // // final roleId = ref.read(userRoleProvider); + // + // // print("ENQroleId - $roleId"); + // + // }); + } + + Future getClaimsList(id) async { + // print('getClaimList called MagId - $managerId - $role'); + setState(() { + isLoading = true; + }); + // dynamic id = widget.policyNumber; + print('POLID - $id'); + try { + final response = await apiService.findSingleClaimData(id); + + if (response['status'] == 'success') { + final data = response['data']; + print('getClaimsListData - ${response['data']}'); + setState(() { + if (data is List) { + // Already a list of maps + getStaffData = List>.from(data); + } else if (data is Map) { + // Single object, wrap in a list + getStaffData = [Map.from(data)]; + } else { + getStaffData = []; + } + // getStaffData = List>.from(response['data']); + originalData = getStaffData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getStaffData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + final TextEditingController _searchStaffController = TextEditingController(); + + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat('dd/MM/yyyy HH:mm').format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } + + List _buildPopupMenuActions(BuildContext context, dynamic data) { + return [ + GestureDetector( + onTap: () { + Navigator.pop(context); + print('EDITStaff - ${data['id']}'); + // dynamic id = data['id']; + // context.go('/tabEnquiry/$id'); + + // update provider + final id = data['id'].toString(); + ref.read(enquiryIdProvider.notifier).state = id; + context.go(AppRoutes.tabEnquiry); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18), + SizedBox(width: 10), + Text('Edit'), + ], + ), + ), + ]; + } + + @override + Widget build(BuildContext context) { + return Container( + // color: Colors.yellow.shade50, + width: MediaQuery.of(context).size.width * 0.6, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + // color: Colors.green, + // color: Colors.green.shade50, + width: MediaQuery.of(context).size.width, + + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + if (!ResponsiveLayout.isMobile(context)) + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: const Row( + children: [ + Expanded( + flex: 2, + child: Text('Claim Type', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Claim Amount', style: _headerStyle), + ), + Expanded( + flex: 3, + child: Text('Remarks', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Status', style: _headerStyle), + ), + + Expanded( + flex: 1, + child: Text('Action', style: _headerStyle), + ), + ], + ), + ), + + _buildDataTable(context), + ], + ), + ), + ], + ), + ); + } + + Widget _buildDataTable1(BuildContext context) { + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + final sortedData = [...filteredData]; + return ListView.builder( + itemCount: ResponsiveLayout.isMobile(context) + ? sortedData + .length // only cards for mobile + : sortedData.length + 1, // +1 for header in desktop + itemBuilder: (context, index) { + if (!ResponsiveLayout.isMobile(context) && index == 0) { + return _buildHeader(); + } + + final startIndex = (currentPage - 1) * itemsPerPage; + final item = + sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)]; + final sno = startIndex + index; + + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); + }, + ); + } + + Widget _buildDataTable(BuildContext context) { + print('DATA -1'); + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + print('DATA -2'); + + final sortedData = [...filteredData]; + print('DATA -$sortedData'); + + return ListView.builder( + shrinkWrap: true, // 👈 important when inside Column + physics: const NeverScrollableScrollPhysics(), // let parent scroll + itemCount: sortedData.length, + itemBuilder: (context, index) { + print('DAta Itembuilder 1'); + final startIndex = (currentPage - 1) * itemsPerPage; + final item = sortedData[index]; + final sno = startIndex + index + 1; + + print('DAta Itembuilder 2'); + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); + }, + ); + } + + Widget _buildHeader() { + return SizedBox.shrink(); + } + + Widget _buildDataRow(Map item, sno) { + print('Build - $item'); // Debug: check data + return Container( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16), + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + border: const Border( + bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Expanded( + flex: 2, + child: Text(item['claim_type_value'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 2, + child: Text(item['claim_amount'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 3, + child: Text(item['claim_description'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 2, + child: Text(item['claim_status_value'] ?? '-', style: _dataBold), + ), + + Expanded( + flex: 1, + child: Row( + children: [ + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: Offset(0, 30), + icon: Icon( + Icons.more_vert, + color: Color(0xFF475569), + size: 14, + ), + itemBuilder: (context) => [ + CustomPopupMenuEntry( + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: _buildPopupMenuActions(context, item), + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildDataCard(Map item, int sno) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + // color: const Color(0xFFF6FEFD), + color: const Color(0xFFFFFFFF), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: const Color(0xffD9EBE8)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Title + menu + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item['claim_type_value'] ?? '-', + style: _headerStyle, + ), + ), + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: const Offset(0, 30), + icon: const Icon( + Icons.more_vert, + color: Color(0xFF475569), + size: 16, + ), + itemBuilder: (context) => [ + PopupMenuItem( + value: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: _buildPopupMenuActions(context, item), + ), + ), + ], + ), + ], + ), + // Description + Text( + item['claim_description'] ?? '-', + style: _cardBodyStyle, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + // Status + Row( + children: [ + const Text( + "Status: ", + style: TextStyle( + color: Colors.green, + fontWeight: FontWeight.w600, + fontSize: 12, + ), + ), + Text( + item['claim_status_value'] ?? '-', + style: TextStyle( + // color: (item['status'] == "Completed") + // ? Colors.green + // : Colors.orange, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ], + ), + ); + } + + static final _dataBold = TextStyle( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = TextStyle( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + static const _headerStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ); + static const _cardheaderStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static const _cardBodyStyle = TextStyle( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); +} diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/sub_endrosment.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/sub_endrosment.dart new file mode 100644 index 0000000..adc5f37 --- /dev/null +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/sub_endrosment.dart @@ -0,0 +1,464 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:http/http.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; +import '../../../../core/routing/routes.dart'; +import '../../../../core/services/api_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../widgets/custom_action_popup.dart'; + +class EndrosmentSubList extends ConsumerStatefulWidget { + final dynamic policyNumber; + const EndrosmentSubList({super.key, this.policyNumber}); + @override + ConsumerState createState() => EndrosmentSubListState(); +} + +class EndrosmentSubListState extends ConsumerState { + int currentPage = 1; + int itemsPerPage = 10; + late ApiService apiService; + + // List> dataVal = []; + List> getStaffData = []; + List> originalData = []; + List> filteredData = []; + bool isLoading = false; + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + if (widget.policyNumber != null) { + getEndrosmentList(widget.policyNumber); + } + // Future.microtask(() { + // // final id = ref.read(managerIdProvider); + // // final roleId = ref.read(userRoleProvider); + // + // }); + } + + Future getEndrosmentList(id) async { + print('POLID - $id'); + // print('getClaimList called MagId - $managerId - $role'); + setState(() { + isLoading = true; + }); + // dynamic id = widget.policyNumber; + try { + final response = await apiService.findSingleEnrosmentData(id); + + if (response['status'] == 'success') { + final data = response['data']; + print('getEndrosmentData - ${response['data']}'); + setState(() { + if (data is List) { + print('getEndrosmentData 1'); + // Already a list of maps + getStaffData = List>.from(data); + } else if (data is Map) { + print('getEndrosmentData 2 '); + // Single object, wrap in a list + + getStaffData = [Map.from(data)]; + + print('getEndrosmentData 2 - $getStaffData'); + } else { + print('getEndrosmentData 3'); + getStaffData = []; + } + // getStaffData = List>.from(response['data']); + originalData = getStaffData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getStaffData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + final TextEditingController _searchStaffController = TextEditingController(); + + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat('dd/MM/yyyy HH:mm').format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } + + List get _paginatedData { + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + final startIndex = (currentPage - 1) * itemsPerPage; + final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length); + + return sortedData.sublist(startIndex, endIndex); + } + + List _buildPopupMenuActions(BuildContext context, dynamic data) { + return [ + GestureDetector( + onTap: () { + Navigator.pop(context); + print('EDITStaff - ${data['id']}'); + // dynamic id = data['id']; + // context.go('/tabEnquiry/$id'); + + // update provider + final id = data['id'].toString(); + ref.read(enquiryIdProvider.notifier).state = id; + context.go(AppRoutes.tabEnquiry); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.edit_sharp, color: Color(0xFF319718), size: 18), + SizedBox(width: 10), + Text('Edit'), + ], + ), + ), + ]; + } + + @override + Widget build(BuildContext context) { + return Container( + // color: Colors.yellow.shade50, + width: MediaQuery.of(context).size.width * 0.6, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + // color: Colors.green, + // color: Colors.green.shade50, + width: MediaQuery.of(context).size.width, + + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + if (!ResponsiveLayout.isMobile(context)) + Container( + decoration: BoxDecoration( + color: Colors.white, + // color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: const Row( + children: [ + Expanded( + flex: 2, + child: Text('Endorsement Type', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text( + 'Endorsement Number', + style: _headerStyle, + ), + ), + + Expanded( + flex: 3, + child: Text('Remarks', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Status', style: _headerStyle), + ), + + Expanded( + flex: 1, + child: Text('Action', style: _headerStyle), + ), + ], + ), + ), + + _buildDataTable(context), + ], + ), + ), + ], + ), + ); + } + + Widget _buildDataTable1(BuildContext context) { + print('DATA -1'); + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + print('DATA -2'); + // final sortedData = [..._paginatedData]; + final sortedData = [...filteredData]; + print('DATA -$sortedData'); + return ListView.builder( + itemCount: ResponsiveLayout.isMobile(context) + ? sortedData + .length // only cards for mobile + : sortedData.length + 1, // +1 for header in desktop + // itemCount: sortedData.length, + itemBuilder: (context, index) { + print('DAta Itembuilder'); + if (!ResponsiveLayout.isMobile(context) && index == 0) { + return _buildHeader(); + } + print('DAta Itembuilder 1'); + final startIndex = (currentPage - 1) * itemsPerPage; + print('DAta Itembuilder 2'); + final item = + sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)]; + final sno = startIndex + index; + + print('DAta Itembuilder 3'); + // return _buildDataRow(item, sno); + + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); + }, + ); + } + + Widget _buildDataTable(BuildContext context) { + print('DATA -1'); + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + print('DATA -2'); + + final sortedData = [...filteredData]; + print('DATA -$sortedData'); + + return ListView.builder( + shrinkWrap: true, // 👈 important when inside Column + physics: const NeverScrollableScrollPhysics(), // let parent scroll + itemCount: sortedData.length, + itemBuilder: (context, index) { + print('DAta Itembuilder 1'); + final startIndex = (currentPage - 1) * itemsPerPage; + final item = sortedData[index]; + final sno = startIndex + index + 1; + + print('DAta Itembuilder 2'); + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); + }, + ); + } + + Widget _buildHeader() { + return SizedBox.shrink(); + } + + Widget _buildDataRow(Map item, sno) { + print('Build - $item'); // Debug: check data + return Container( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16), + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + border: const Border( + bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Expanded( + flex: 2, + child: Text( + item['endorsement_type_value'] ?? '-', + style: _dataBold, + ), + ), + Expanded( + flex: 2, + child: Text(item['endorsement_no'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 3, + child: Text( + item['endorsement_description'] ?? '-', + style: _dataBold, + ), + ), + Expanded( + flex: 2, + child: Text(item['status'] ?? '-', style: _dataBold), + ), + + Expanded( + flex: 1, + child: Row( + children: [ + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: Offset(0, 30), + icon: Icon( + Icons.more_vert, + color: Color(0xFF475569), + size: 14, + ), + itemBuilder: (context) => [ + CustomPopupMenuEntry( + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 8, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: _buildPopupMenuActions(context, item), + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildDataCard(Map item, int sno) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xFFFFFFFF), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: const Color(0xffD9EBE8)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Title + menu + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item['endorsement_type_value'] ?? '-', + style: _headerStyle, + ), + ), + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: const Offset(0, 30), + icon: const Icon( + Icons.more_vert, + color: Color(0xFF475569), + size: 16, + ), + itemBuilder: (context) => [ + PopupMenuItem( + value: 1, + child: Column( + mainAxisSize: MainAxisSize.min, + children: _buildPopupMenuActions(context, item), + ), + ), + ], + ), + ], + ), + // Description + Text( + item['endorsement_description'] ?? '-', + style: _cardBodyStyle, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + // Status + Row( + children: [ + const Text( + "Status: ", + style: TextStyle( + color: Colors.green, + fontWeight: FontWeight.w600, + fontSize: 12, + ), + ), + Text( + item['status'] ?? '-', + style: TextStyle( + // color: (item['status'] == "Completed") + // ? Colors.green + // : Colors.orange, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ], + ), + ); + } + + static final _dataBold = TextStyle( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = TextStyle( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + static const _headerStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ); + static const _cardheaderStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static const _cardBodyStyle = TextStyle( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); +} diff --git a/lib/presentation/screens/UserManagement/Agent/agent.dart b/lib/presentation/screens/UserManagement/Agent/agent.dart index 6c52aeb..ee694e7 100644 --- a/lib/presentation/screens/UserManagement/Agent/agent.dart +++ b/lib/presentation/screens/UserManagement/Agent/agent.dart @@ -547,25 +547,25 @@ class AgentState extends ConsumerState { // color: Colors.white, child: Row( children: [ - IconButton( - onPressed: () { - setState(() { - docUploadedFile = null; - passportFileUrlFromApi = null; - selectedFileNames = null; - }); - }, - icon: Icon( - Icons.remove_circle_outline_rounded, - color: Colors.redAccent, - ), - tooltip: 'To Remove Upload', - ), + // IconButton( + // onPressed: () { + // setState(() { + // docUploadedFile = null; + // passportFileUrlFromApi = null; + // selectedFileNames = null; + // }); + // }, + // icon: Icon( + // Icons.remove_circle_outline_rounded, + // color: Colors.redAccent, + // ), + // tooltip: 'To Remove Upload', + // ), GestureDetector( onTap: () => apiService.downloadFile( apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId', - apiId: null, + apiId: selectedId, localFile: docUploadedFile, fileName: selectedFileNames, ), diff --git a/lib/presentation/themes/indicators/input_field_decoration.dart b/lib/presentation/themes/indicators/input_field_decoration.dart index 0e17127..b403f38 100644 --- a/lib/presentation/themes/indicators/input_field_decoration.dart +++ b/lib/presentation/themes/indicators/input_field_decoration.dart @@ -13,6 +13,7 @@ class AppInputDecorations { borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFFFFFFFF)), ), + errorStyle: const TextStyle(color: Colors.red, fontSize: 12), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFFFFFFFF)), @@ -21,6 +22,15 @@ class AppInputDecorations { borderRadius: BorderRadius.circular(10), borderSide: const BorderSide(color: Color(0xFF50A398), width: 2), ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFD83731), width: 1), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide(color: Color(0xFFD83731), width: 2), + ), floatingLabelBehavior: FloatingLabelBehavior.never, ); } diff --git a/lib/presentation/themes/indicators/text_field_theme.dart b/lib/presentation/themes/indicators/text_field_theme.dart index 627ca76..87c8cfe 100644 --- a/lib/presentation/themes/indicators/text_field_theme.dart +++ b/lib/presentation/themes/indicators/text_field_theme.dart @@ -136,6 +136,9 @@ class ThemedFormField extends HookWidget { keyboardType: keyboardType, // ✅ e.g. TextInputType.number maxLength: maxLength, // ✅ max length inputFormatters: inputFormatters, + // ✅ allow multiline if user sets maxLines / minLines + minLines: (keyboardType == TextInputType.multiline) ? 3 : 1, + maxLines: (keyboardType == TextInputType.multiline) ? null : 1, ), ), ); diff --git a/lib/presentation/widgets/drawer_menu.dart b/lib/presentation/widgets/drawer_menu.dart index 277f98b..a5bfed1 100644 --- a/lib/presentation/widgets/drawer_menu.dart +++ b/lib/presentation/widgets/drawer_menu.dart @@ -83,19 +83,19 @@ class DrawerMenuState extends ConsumerState { ), ), ), - const SizedBox(height: 5), - GestureDetector( - onTap: () { - context.go(AppRoutes.enquiryLst); - }, - child: const Text( - "Enquiries", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - ), - ), - ), + // const SizedBox(height: 5), + // GestureDetector( + // onTap: () { + // context.go(AppRoutes.enquiryLst); + // }, + // child: const Text( + // "Enquiries", + // style: TextStyle( + // fontSize: 16, + // fontWeight: FontWeight.w400, + // ), + // ), + // ), const SizedBox(height: 5), GestureDetector( onTap: () { @@ -230,8 +230,12 @@ class DrawerMenuState extends ConsumerState { builder: (context, ref, _) { return IconButton( onPressed: () { - ref.read(enquiryIdProvider.notifier).state = null; - context.go(AppRoutes.tabEnquiry); + if (roleId == 'manager') { + } else if (roleId == 'agent') { + context.go(AppRoutes.enquiryLst); + } + // ref.read(enquiryIdProvider.notifier).state = null; + // context.go(AppRoutes.tabEnquiry); }, icon: const Icon( Icons.list_alt_rounded, diff --git a/lib/presentation/widgets/topbar.dart b/lib/presentation/widgets/topbar.dart index 9657877..316abef 100644 --- a/lib/presentation/widgets/topbar.dart +++ b/lib/presentation/widgets/topbar.dart @@ -39,15 +39,15 @@ class TopBar extends StatelessWidget implements PreferredSizeWidget { width: 120, ), if (isMobile) ...[ - IconButton( - icon: const Icon( - Icons.arrow_back_ios, - color: Colors.black87, - size: 18, - ), - onPressed: onBack ?? () => Navigator.pop(context), - ), - + // IconButton( + // icon: const Icon( + // Icons.arrow_back_ios, + // color: Colors.black87, + // size: 18, + // ), + // onPressed: onBack ?? () => Navigator.pop(context), + // ), + SizedBox(width: 5), Expanded( child: Text( title,