From 722d8e49044446522df12a590c96d29e89935e8d Mon Sep 17 00:00:00 2001 From: SurendarSuri30 Date: Sat, 7 Mar 2026 11:39:46 +0530 Subject: [PATCH] Endorsement full completed --- .flutter-plugins-dependencies | 2 +- lib/core/config/env.dart | 4 +- lib/core/routing/app_router.dart | 48 +- lib/core/routing/routes.dart | 3 +- lib/core/services/api_service.dart | 51 +- lib/presentation/layouts/appheader.dart | 29 +- .../screens/Enquiry/enquiry/policy_popup.dart | 60 +- .../create_endorsement_dialog.dart | 2620 ++++++++++++++ .../endorsomentUpdateValidation.dart | 3025 +++++++++++++++++ .../policy_claims_endros/endrosment.dart | 1630 +++++++-- .../UserManagement/Agent/agentList.dart | 3 +- .../staff/policy/policy_validation.dart | 70 +- lib/presentation/widgets/drawer_menu.dart | 2 +- lib/presentation/widgets/drawer_menu1.dart | 2 +- lib/presentation/widgets/mobile_tabs.dart | 2 +- pubspec.lock | 20 +- web/index.html | 4 +- 17 files changed, 7165 insertions(+), 410 deletions(-) create mode 100644 lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart create mode 100644 lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 9ad04a4..44d1f0e 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/venba/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.2.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_ios-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/home/venba/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"syncfusion_flutter_pdfviewer","path":"/home/venba/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-31.1.19/","native_build":true,"dependencies":["device_info_plus"],"dev_dependency":false},{"name":"url_launcher_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.31/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/venba/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_android-7.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_android","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_android-1.0.52/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"open_file_android","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_android-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_android-2.2.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/home/venba/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.13/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"syncfusion_flutter_pdfviewer","path":"/home/venba/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-31.1.19/","native_build":true,"dependencies":["device_info_plus"],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.20/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.2.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_mac","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_mac-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/home/venba/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"syncfusion_pdfviewer_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_macos-31.1.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_linux-0.0.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"syncfusion_pdfviewer_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_linux-31.1.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_windows-1.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_windows-0.0.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"syncfusion_pdfviewer_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_windows-31.1.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","dependencies":[],"dev_dependency":false},{"name":"firebase_auth_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth_web-6.1.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core_web-3.3.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.1.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"flutter_secure_storage_web","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/venba/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_web-1.1.0/","dependencies":[],"dev_dependency":false},{"name":"open_file_web","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_web-0.0.4/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/home/venba/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"syncfusion_pdfviewer_web","path":"/home/venba/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_web-31.1.19/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.1/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":[]},{"name":"device_info_plus","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"local_auth","dependencies":["local_auth_android","local_auth_darwin","local_auth_windows"]},{"name":"local_auth_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"local_auth_darwin","dependencies":[]},{"name":"local_auth_windows","dependencies":[]},{"name":"open_file","dependencies":["open_file_android","open_file_web","open_file_ios","open_file_mac","open_file_windows","open_file_linux"]},{"name":"open_file_android","dependencies":[]},{"name":"open_file_ios","dependencies":[]},{"name":"open_file_linux","dependencies":[]},{"name":"open_file_mac","dependencies":[]},{"name":"open_file_web","dependencies":[]},{"name":"open_file_windows","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"pdf_render","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"syncfusion_flutter_pdfviewer","dependencies":["url_launcher","device_info_plus","syncfusion_pdfviewer_web","syncfusion_pdfviewer_macos","syncfusion_pdfviewer_windows","syncfusion_pdfviewer_linux"]},{"name":"syncfusion_pdfviewer_linux","dependencies":[]},{"name":"syncfusion_pdfviewer_macos","dependencies":[]},{"name":"syncfusion_pdfviewer_web","dependencies":[]},{"name":"syncfusion_pdfviewer_windows","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2026-02-03 17:07:24.283936","version":"3.32.1","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.2.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_ios","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/open_file_ios-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"syncfusion_flutter_pdfviewer","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-31.1.19/","native_build":true,"dependencies":["device_info_plus"],"dev_dependency":false},{"name":"url_launcher_ios","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_auth","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.31/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/google_sign_in_android-7.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_android","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/local_auth_android-1.0.52/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"open_file_android","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/open_file_android-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/path_provider_android-2.2.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.13/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"syncfusion_flutter_pdfviewer","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/syncfusion_flutter_pdfviewer-31.1.19/","native_build":true,"dependencies":["device_info_plus"],"dev_dependency":false},{"name":"url_launcher_android","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.20/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.4/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage_macos","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.2.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_mac","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/open_file_mac-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"syncfusion_pdfviewer_macos","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_macos-31.1.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_linux","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_linux","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/open_file_linux-0.0.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"syncfusion_pdfviewer_linux","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_linux-31.1.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_linux","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_auth-6.1.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_core-4.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/local_auth_windows-1.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/open_file_windows-0.0.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"syncfusion_pdfviewer_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_windows-31.1.19/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_windows","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","dependencies":[],"dev_dependency":false},{"name":"device_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/device_info_plus-11.5.0/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/file_picker-10.3.7/","dependencies":[],"dev_dependency":false},{"name":"firebase_auth_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_auth_web-6.1.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_core_web-3.3.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.1.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"flutter_secure_storage_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/fluttertoast-9.0.0/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/google_sign_in_web-1.1.0/","dependencies":[],"dev_dependency":false},{"name":"open_file_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/open_file_web-0.0.4/","dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","dependencies":[],"dev_dependency":false},{"name":"pdf_render","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/pdf_render-1.4.12/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"syncfusion_pdfviewer_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/syncfusion_pdfviewer_web-31.1.19/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/Users/venbateam/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.1/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"connectivity_plus","dependencies":[]},{"name":"device_info_plus","dependencies":[]},{"name":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_auth","dependencies":["firebase_auth_web","firebase_core"]},{"name":"firebase_auth_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_secure_storage","dependencies":["flutter_secure_storage_linux","flutter_secure_storage_macos","flutter_secure_storage_web","flutter_secure_storage_windows"]},{"name":"flutter_secure_storage_linux","dependencies":[]},{"name":"flutter_secure_storage_macos","dependencies":[]},{"name":"flutter_secure_storage_web","dependencies":[]},{"name":"flutter_secure_storage_windows","dependencies":["path_provider"]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"local_auth","dependencies":["local_auth_android","local_auth_darwin","local_auth_windows"]},{"name":"local_auth_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"local_auth_darwin","dependencies":[]},{"name":"local_auth_windows","dependencies":[]},{"name":"open_file","dependencies":["open_file_android","open_file_web","open_file_ios","open_file_mac","open_file_windows","open_file_linux"]},{"name":"open_file_android","dependencies":[]},{"name":"open_file_ios","dependencies":[]},{"name":"open_file_linux","dependencies":[]},{"name":"open_file_mac","dependencies":[]},{"name":"open_file_web","dependencies":[]},{"name":"open_file_windows","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"pdf_render","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"syncfusion_flutter_pdfviewer","dependencies":["url_launcher","device_info_plus","syncfusion_pdfviewer_web","syncfusion_pdfviewer_macos","syncfusion_pdfviewer_windows","syncfusion_pdfviewer_linux"]},{"name":"syncfusion_pdfviewer_linux","dependencies":[]},{"name":"syncfusion_pdfviewer_macos","dependencies":[]},{"name":"syncfusion_pdfviewer_web","dependencies":[]},{"name":"syncfusion_pdfviewer_windows","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2026-03-04 19:43:07.407497","version":"3.35.7","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/lib/core/config/env.dart b/lib/core/config/env.dart index 1be7b07..dd54391 100644 --- a/lib/core/config/env.dart +++ b/lib/core/config/env.dart @@ -5,8 +5,8 @@ class Env { ); static const String apiUrl = String.fromEnvironment( 'API_URL', - // defaultValue: 'https://partner.nhanceindia.in/partner_api/api/', /* Live build (enable index.html line 18) */ - defaultValue: 'https://venbait.in/nhance/partner/dev/api/', /* Test build (enable index.html line 19) */ + defaultValue: 'https://partner.nhanceindia.in/partner_api/api/', /* Live build (enable index.html line 18) */ + // defaultValue: 'https://venbait.in/nhance/partner/dev/api/', /* Test build (enable index.html line 19) */ // defaultValue: 'http://localhost/nhance_partner_be/', /* localhost build (enable index.html line 19) */ ); // static const String baseUrl = String.fromEnvironment( diff --git a/lib/core/routing/app_router.dart b/lib/core/routing/app_router.dart index 7e4343a..2954141 100644 --- a/lib/core/routing/app_router.dart +++ b/lib/core/routing/app_router.dart @@ -12,6 +12,7 @@ import '../../data/services/auth_service.dart'; import '../../presentation/providers/manager_provider.dart'; import '../../presentation/screens/Enquiry/enquiry/tabs.dart'; import '../../presentation/screens/Enquiry/policy_claims_endros/claims.dart'; +import '../../presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart'; import '../../presentation/screens/Enquiry/policy_claims_endros/endrosment.dart'; import '../../presentation/screens/Masters/Brokers/brokerList.dart'; import '../../presentation/screens/Masters/EndorsementType/endorsementList.dart'; @@ -188,8 +189,8 @@ final GoRouter appRouter = GoRouter( builder: (context, state) => const claimList(), ), GoRoute( - path: AppRoutes.endosement, - builder: (context, state) => const endosement(), + path: AppRoutes.Endorsement, + builder: (context, state) => const Endorsement(), ), GoRoute( path: AppRoutes.policylist, @@ -231,6 +232,49 @@ final GoRouter appRouter = GoRouter( }, ), + GoRoute( + path: AppRoutes.endorsomentValidation, + name: "endorsomentValidation", + pageBuilder: (context, state) { + + final extra = state.extra as Map; + + return CustomTransitionPage( + key: state.pageKey, + opaque: true, + barrierColor: Colors.black.withOpacity(0.3), + fullscreenDialog: true, + transitionDuration: const Duration(milliseconds: 1000), + + child: endorsomentValidation( + title: extra["title"], + userId: extra["userId"], + managerId: extra["managerId"], + role: extra["role"], + item: extra["item"], + onSubmit: (value) { + debugPrint("Validation Done: $value"); + }, + ), + + transitionsBuilder: (context, animation, secondaryAnimation, child) { + final curved = CurvedAnimation( + parent: animation, + curve: Curves.easeOutCubic, + ); + + return SlideTransition( + position: Tween( + begin: const Offset(0, 1), + end: Offset.zero, + ).animate(curved), + child: child, + ); + }, + ); + }, + ), + GoRoute( path: AppRoutes.quotation, builder: (context, state) => const QuotationScreen(), diff --git a/lib/core/routing/routes.dart b/lib/core/routing/routes.dart index 1e7c83f..7244ffb 100644 --- a/lib/core/routing/routes.dart +++ b/lib/core/routing/routes.dart @@ -20,9 +20,10 @@ class AppRoutes { static const String individualAttendance = '/individualAttendance'; static const String claimlist = '/claimList'; - static const String endosement = '/endosement'; + static const String Endorsement = '/Endorsement'; static const String policylist = '/policylist'; static const String policyValidation = '/policyValidation'; + static const String endorsomentValidation = '/endorsomentValidation'; static const String quotation = '/QuotationScreen'; static const String policy = '/PolicyScreen'; static const String policyStaffEnq = '/policyStaffEnq'; diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 4384bc2..537ffc7 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -1565,37 +1565,52 @@ class ApiService { // ----------------------------------- ENDORSEMENT ------------------------------------------------- Future> fetchEndorsementList( - managerId, - int id, - role, - ) async { - // print(_token); + managerId, + int id, + role, { + String? fromDate, + String? toDate, + String? endorsementType, + String? insurerId, + String? status, + String? verification, + }) async { + print('fetchEndorsementList in'); if (_token == null) { await _initializeToken(); } + print('fetchEndorsementList token'); - final url; + Map queryParams = {}; - if (role == 'manager') { - url = Uri.parse( - '${Env.apiUrl}endorsement/endorsementList?manager_id=$managerId', - ); - } else if (role == 'Accounts') { - url = Uri.parse( - '${Env.apiUrl}endorsement/endorsementList?manager_id=$managerId', - ); + // 🔹 Role based base params + if (role == 'manager' || role == 'Accounts') { + queryParams['manager_id'] = managerId.toString(); } else if (role == 'agent') { - url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?agent_id=$id'); + queryParams['agent_id'] = id.toString(); } else if (role == 'handler') { - url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?handler_id=$id'); + queryParams['handler_id'] = id.toString(); } else { - url = Uri.parse('${Env.apiUrl}endorsement/endorsementList?staff_id=$id'); + queryParams['staff_id'] = id.toString(); } + queryParams['from_date'] = fromDate ?? ''; + queryParams['to_date'] = toDate ?? ''; + queryParams['endorsement_type'] = endorsementType ?? ''; + queryParams['insurer_id'] = insurerId ?? ''; + queryParams['status'] = status ?? ''; + queryParams['verification'] = verification ?? ''; + + print('fetchEndorsementList api'); + + final url = Uri.parse('${Env.apiUrl}endorsement/endorsementList') + .replace(queryParameters: queryParams); + final headers = { - 'Authorization': 'Bearer $_token' ?? '', + 'Authorization': 'Bearer $_token', 'app-signature': Env.App_Signature, }; + final response = await _makeGetRequest(url, headers); return response; } diff --git a/lib/presentation/layouts/appheader.dart b/lib/presentation/layouts/appheader.dart index 04a0967..dbe7815 100644 --- a/lib/presentation/layouts/appheader.dart +++ b/lib/presentation/layouts/appheader.dart @@ -84,6 +84,8 @@ class _AppHeaderState extends ConsumerState { } else if (currentRoute.contains('invoice') || // ✅ ADD THIS currentRoute.contains('payout')) { _activeMenu = 'Invoice'; + } else if (currentRoute.contains('Endorsement')) { + _activeMenu = 'Endorsement'; } }); }); @@ -268,14 +270,6 @@ class _AppHeaderState extends ConsumerState { }, ), const SizedBox(height: 2), - _buildPopupItem( - label: "Endorsement", - onTap: () { - _hidePopup(); - context.go(AppRoutes.endosement); - }, - ), - const SizedBox(height: 2), _buildPopupItem( label: "Policy", onTap: () { @@ -384,6 +378,9 @@ class _AppHeaderState extends ConsumerState { const SizedBox(width: 15), ], + SizedBox(width: 8), + + // Enquiry if (role != 'Accounts') ...[ _buildMenuItem( @@ -402,6 +399,21 @@ class _AppHeaderState extends ConsumerState { }, ), ], + const SizedBox(width: 8), + + _buildMenuItem( + isActive: _activeMenu == 'Endorsement', + icon: Icons.checklist_outlined, + label: "Endorsement", + onTap: () async { + _hidePopup(); + setState(() => _activeMenu = 'Endorsement'); + await _clearDashboardFilters(); + context.go(AppRoutes.Endorsement); + }, + ), + + const SizedBox(width: 8), @@ -453,6 +465,7 @@ class _AppHeaderState extends ConsumerState { ), ], + const Spacer(), // Raise Enquiry button for agents diff --git a/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart b/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart index d6179e7..1e7daa2 100644 --- a/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart +++ b/lib/presentation/screens/Enquiry/enquiry/policy_popup.dart @@ -191,6 +191,37 @@ class _AddDialogState extends State { } } + Future getVehicleListSearchData(String val) async { + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchVehicleSearch(val); + + if (response['status'] == 'success') { + print('E113 => getStaffListData => ${response['data']}'); + setState(() { + getVehicleListData = List>.from( + response['data'], + ); + originalVehicleData = getVehicleListData; + filteredVehicleData = List.from(originalVehicleData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getVehicleListData = []; + originalVehicleData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + Future getPolicyListSearchData1(val) async { setState(() { isLoading = true; @@ -225,36 +256,7 @@ class _AddDialogState extends State { } } - Future getVehicleListSearchData(String val) async { - setState(() { - isLoading = true; - }); - try { - final response = await apiService.fetchVehicleSearch(val); - - if (response['status'] == 'success') { - print('E113 => getStaffListData => ${response['data']}'); - setState(() { - getVehicleListData = List>.from( - response['data'], - ); - originalVehicleData = getVehicleListData; - filteredVehicleData = List.from(originalVehicleData); - // print('originalData - $getClaimPolicies'); - }); - } else { - getVehicleListData = []; - originalVehicleData = []; - } - } catch (e) { - print('Exception occurred: $e'); - } finally { - setState(() { - isLoading = false; - }); - } - } Future getStaffList( dynamic managerId, diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart new file mode 100644 index 0000000..9a906d5 --- /dev/null +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/create_endorsement_dialog.dart @@ -0,0 +1,2620 @@ +import 'dart:convert'; +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +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 '../../../providers/manager_provider.dart'; +import '../../../providers/userRoleProvider.dart'; +import '../../../themes/indicators/customizd_file_upload.dart'; +import '../../../themes/indicators/input_field_decoration.dart'; +import '../../../themes/indicators/search_field_theme.dart'; +import '../../../themes/indicators/text_field_theme.dart'; + +class CreateEndorsementDialog extends ConsumerStatefulWidget { + final String title; + final dynamic userId; + final dynamic managerId; + final dynamic role; + final void Function(String value) onSubmit; + + const CreateEndorsementDialog({ + super.key, + required this.title, + required this.onSubmit, + required this.userId, + required this.managerId, + required this.role, + }); + @override + ConsumerState createState() => + _CreateEndorsementDialogState(); +} + +class _CreateEndorsementDialogState + extends ConsumerState { + late ApiService apiService; + bool isLoading = false; + bool isSubmitLoading = false; + + dynamic userId; + dynamic roleId; + dynamic managerId; + + late TextEditingController controller; + Map controllers = {}; + + String lifecycleStatus = "Open"; // default + String verificationStatus = "To Verify"; // default + + bool isPolicyNumberReadOnly = true; + bool showSearchSection = true; + + /// 🔥 ADD STEP VARIABLES HERE + int currentStep = 1; + + bool step1Completed = false; + bool step2Completed = false; + bool step3Completed = false; + bool step4Completed = false; + + final _formKey = GlobalKey(); + String? _token; + String? selectedClaimFileNames; + String? selectedEndorsement; + // String? selectedEndrosementPolicyFrom; + String? selectedEndrosementPolicyFrom = "Internal"; + String? selectedFileNames; + String? selectedPaymentModeId; + + bool isPolicyFromFocused = false; + bool isEndorsementTypeFocused = false; + bool isInsurerFocused = false; + bool isBrokerFocused = false; + bool isPolicyNumberFocused = false; + + bool isRegNoFocused = false; + bool isInsuredNameFocused = false; + bool isEndorsementNoFocused = false; + bool isContactPersonFocused = false; + bool isPendingDaysFocused = false; + bool isPremiumFocused = false; + bool isCommissionFocused = false; + bool isStartDateFocused = false; + bool isEndDateFocused = false; + bool isPaymentModeFocused = false; + + String policyFrom = "Internal"; + String financialOrNonFinancial = "Yes"; + + PlatformFile? uploadedFile; + + final _formKeyEndrosment = GlobalKey(); + final GlobalKey>> dropDownKey = + GlobalKey>>(); + final GlobalKey>> + dropDownKeyEndorsement = + GlobalKey>>(); + + final TextEditingController _vehicleSearchController = + TextEditingController(); + final TextEditingController _policySearchController = TextEditingController(); + + /// Controllers + final TextEditingController policyNumber = TextEditingController(); + final TextEditingController endorsementDescription = TextEditingController(); + final TextEditingController contactPerson = TextEditingController(); + final TextEditingController pendingDays = TextEditingController(); + final TextEditingController premium = TextEditingController(); + final TextEditingController commission = TextEditingController(); + // 🔹 NEW CONTROLLERS + final TextEditingController regNoController = TextEditingController(); + final TextEditingController insuredNameController = TextEditingController(); + final TextEditingController endorsementNoController = TextEditingController(); + final TextEditingController contactPersonController = TextEditingController(); + // final TextEditingController pendingDaysController = TextEditingController(); + final TextEditingController premiumController = TextEditingController(); + final TextEditingController commissionController = TextEditingController(); + final TextEditingController policyStartController = TextEditingController(); + final TextEditingController policyEndController = TextEditingController(); + + // 🔹 DROPDOWN VALUES + String? selectedInsurer; + String? selectedBroker; + String? selectedEndorsementNo; + // String? selectedInsuredName; + String financialType = "Yes"; + + // 🔹 LISTS + List> insurerList = []; + List> brokerList = []; + List> endorsementNoList = []; + List> insuredNameList = []; + + PlatformFile? docUploadedEndorsFile; + + List> getEndrosmentType = []; + List> filteredEndrosmentData = []; + + List> getPolicyListData = []; + List> originalPolicyData = []; + List> filteredPolicyData = []; + + List> getVehicleListData = []; + List> originalVehicleData = []; + List> filteredVehicleData = []; + + List> getPolicyData = []; + List> originalData = []; + List> filteredData = []; + + List> getPaymentModeData = []; + List> filteredPaymentModeData = []; + + final List> policyFromOptions = [ + {"policy_from": "Internal"}, + {"policy_from": "External"}, + ]; + + bool isInternal = false; + bool isExternal = false; + bool showFinancialFields = true; + + Map endrosmentDetails() { + Map data = { + "policy_number": controllers["policyNum"]?.text, + "endorsement_type": selectedEndorsement, + "policy_from": selectedEndrosementPolicyFrom, + "manager_id": widget.managerId, + "created_by": widget.userId, + "endorsement_description": controllers["remarks"]?.text, + "lifecycle_status": lifecycleStatus, + "verification_status": verificationStatus, + }; + + if (isInternal) { + data.addAll({ + "endorsement_no": endorsementNoController.text, + "contact_person": contactPersonController.text, + // "pending_days": pendingDaysController.text, + "financia_or_non_financial": financialType, + }); + + if (showFinancialFields) { + data.addAll({ + "payment_mode_id": selectedPaymentModeId, + "endorsement_premium": premiumController.text, + "commission_amount": commissionController.text, + }); + } + } + + if (isExternal) { + data.addAll({ + "insurer_id": selectedInsurer, + "insured_name": insuredNameController.text, + "policy_start_date": policyStartController.text, + "policy_end_date": policyEndController.text, + "reg_no": regNoController.text, + "broker_id": selectedBroker, + "endorsement_no": endorsementNoController.text, + "contact_person": contactPersonController.text, + // "pending_days": pendingDaysController.text, + "financia_or_non_financial": financialType, + "endorsement_premium": premiumController.text, + "commission_amount": commissionController.text, + }); + + if (showFinancialFields) { + data.addAll({ + "payment_mode_id": selectedPaymentModeId, + "endorsement_premium": premiumController.text, + "commission_amount": commissionController.text, + }); + } + } + + return data; + } + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + + // ✅ INITIALIZE CONTROLLERS MAP + controllers = { + 'policyNum': TextEditingController(), + 'remarks': TextEditingController(), + 'startDate': TextEditingController(), + 'endDate': TextEditingController(), + }; + + Future.microtask(() async { + managerId = ref.read(managerIdProvider); + roleId = ref.read(userRoleProvider); + userId = ref.read(userIdProvider); + + if (userId != null) { + await getStaffList(managerId, userId, roleId); + } + }); + + if(selectedEndrosementPolicyFrom == 'Internal'){ + + isInternal = true; + + } + + + _initializeToken(); + getEnroementType(); + getBroker(); + getPaymentMode(); + getInsurerDetails(); + } + + @override + void dispose() { + _vehicleSearchController.dispose(); + _policySearchController.dispose(); + + for (var controller in controllers.values) { + controller.dispose(); + } + + super.dispose(); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + 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; + }); + } + } + + Future getPaymentMode() async { + print('getPaymentMode called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('PaymentMode'); + + if (response['status'] == 200) { + print('getPaymentModeData - ${response['data']}'); + setState(() { + getPaymentModeData = List>.from( + response['data'], + ); + print('API Data - $getPaymentModeData'); + + filteredPaymentModeData = List.from(getPaymentModeData); + print('originalData - $filteredPaymentModeData'); + }); + } else { + getPaymentModeData = []; + filteredPaymentModeData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + // Get Broker List + Future getBroker() async { + print('getBroker called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('Broker'); + + if (response['status'] == 200) { + print('getBroker - ${response['data']}'); + setState(() { + brokerList = List>.from(response['data']); + print('API Data - $brokerList'); + + // filteredBrokerData = List.from(getBrokerData); + // print('originalData - $filteredBrokerData'); + }); + } else { + brokerList = []; + // filteredBrokerData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getInsurerDetails() async { + setState(() { + isLoading = true; + }); + try { + final response = await apiService.fetchMasterDropDown('Insurers'); + + print("***999999999999999999*********** $response"); + + if (response['status'] == 200) { + print('getInsurerDetails - ${response['data']}'); + + setState(() { + insurerList = List>.from(response['data']); + + // filteredInsurerData = + // List>.from(getInsurerDetailsData); + // + // print("Filtered Insurer Data: $filteredInsurerData"); + }); + } else { + setState(() { + insurerList = []; + // filteredInsurerData = []; + }); + } + } catch (e) { + print('Error: $e'); + } finally { + setState(() { + isLoading = true; + }); + } + } + + Future getPolicyListSearchData(String val) async { + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchPolicySearch(val); + + if (response['status'] == 'success' && response['data'] != null) { + final dataList = List>.from(response['data']); + setState(() { + getPolicyListData = dataList; + originalPolicyData = dataList; + filteredPolicyData = List.from(originalPolicyData); + }); + } else { + setState(() { + getPolicyListData = []; + originalPolicyData = []; + filteredPolicyData = []; + }); + } + } catch (e) { + print('Exception occurred: $e'); + setState(() { + getPolicyListData = []; + originalPolicyData = []; + filteredPolicyData = []; + }); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getVehicleListSearchData(String val) async { + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchVehicleSearch(val); + + if (response['status'] == 'success') { + print('E113 => getStaffListData => ${response['data']}'); + setState(() { + getVehicleListData = List>.from( + response['data'], + ); + originalVehicleData = getVehicleListData; + filteredVehicleData = List.from(originalVehicleData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getVehicleListData = []; + originalVehicleData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + void validateSteps() { + setState(() { + /// STEP 1 + step1Completed = isExternal + ? true + : controllers['policyNum']!.text.trim().isNotEmpty; + + // STEP 2 → Endorsement Details + step2Completed = + selectedEndorsement != null && + selectedEndrosementPolicyFrom != null && + endorsementNoController.text.trim().isNotEmpty; + + // STEP 3 → Upload & Remarks + step3Completed = controllers['remarks']!.text.trim().isNotEmpty; + + // STEP 4 → Financial + Status + step4Completed = + financialType.isNotEmpty && selectedPaymentModeId != null; + + /// 🔥 ADD STEP SWITCHING LOGIC HERE + if (!step1Completed) { + currentStep = 1; + } else if (!step2Completed) { + currentStep = 2; + } else if (!step3Completed) { + currentStep = 3; + } else { + currentStep = 4; + } + }); + } + + Future getStaffList( + dynamic managerId, + role, + roleId, { + String fromDate = '', + String toDate = '', + }) async { + print('D68 => Fns called => $managerId | $role'); + setState(() { + isLoading = true; + }); + + final id = int.parse(managerId); + // FORCE BOTH VALUES TO STRING + final String managerIdStr = managerId?.toString() ?? ''; + final String roleStr = role?.toString() ?? ''; + + try { + final response = await apiService.fetchPolicyDataOnlyList( + managerIdStr, + roleStr, + roleStr, + fromDate: controllers['startDate']?.text ?? '', + toDate: controllers['endDate']?.text ?? '', + selectedStaffId: widget.userId ?? '', + ); + + if (response['status'] == 'success') { + final data = response['data']; + print('D81 => getStaffListData => ${response['data']}'); + + final fromDate = response['from_date'] ?? ''; + final toDate = response['to_date'] ?? ''; + + print('FromDate : $fromDate'); + print('ToDate : $toDate'); + setState(() { + controllers['startDate']?.text = fromDate; + controllers['endDate']?.text = toDate; + if (data is List) { + // Already a list of maps + getPolicyData = List>.from(data); + } else if (data is Map) { + // Single object, wrap in a list + getPolicyData = [Map.from(data)]; + } else { + getPolicyData = []; + } + // getStaffData = List>.from(response['data']); + originalData = getPolicyData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getPolicyData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + // ================= CREATE API ================= + + Future createUserData(data) async { + if (!mounted) return; + + setState(() { + isSubmitLoading = true; // 🔥 START LOADER + }); + final Uri uri = Uri.parse('${Env.apiUrl}endorsement/createEndorsement'); + + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + // Use MultipartRequest (POST only) + final request = http.MultipartRequest('POST', uri); + request.headers['Authorization'] = 'Bearer $_token'; + request.headers['app-signature'] = Env.App_Signature; + + print("USerDAta - $data"); + + // userData.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + + data.forEach((key, value) { + // if (key != 'certificate_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + // } + }); + // Attach file if selected + if (docUploadedEndorsFile != null) { + try { + if (docUploadedEndorsFile!.bytes != null) { + final multipartFile = http.MultipartFile.fromBytes( + 'endorsement_file_name', + docUploadedEndorsFile!.bytes!, + filename: docUploadedEndorsFile!.name, + ); + request.files.add(multipartFile); + } + // else if (docUploadedEndorsFile!.path != null) { + // final multipartFile = await http.MultipartFile.fromPath( + // 'endorsement_file_name', + // docUploadedEndorsFile!.path!, + // filename: docUploadedEndorsFile!.name, + // ); + // request.files.add(multipartFile); + // } + print("📎 File attached: ${docUploadedEndorsFile!.name}"); + } catch (e) { + print("❌ Failed to attach file: $e"); + } + } + + print(" Sending request with fields: ${request.fields}"); + + try { + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + print("Response status: ${response.statusCode}"); + print("Response body: ${response.body}"); + + if (response.statusCode == 200 || response.statusCode == 201) { + print("✅ Partner submitted successfully!"); + + print("Response: ${response.body}"); + ToastHelper.showSuccessToast(context, 'Saved Successfully'); + Navigator.of(context).pop(); + + widget.onSubmit("success"); + } else if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + } else { + final responseBody = jsonDecode(response.body); + dynamic msg = responseBody['data']; + + print("Failed to submit plan. Status: ${response.statusCode}"); + print("Error: ${response.body}"); + + ToastHelper.showErrorToast(context, 'Failed To Save'); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } finally { + if (mounted) { + setState(() { + isSubmitLoading = false; // 🔥 STOP LOADER + }); + } + } + } + + // ================= UI ================= + + @override + Widget build(BuildContext context) { + return Dialog( + backgroundColor: Colors.transparent, + child: Container( + width: MediaQuery.of(context).size.width * 0.55, + // padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + ), + child: Form( + key: _formKeyEndrosment, + autovalidateMode: AutovalidateMode.disabled, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + /// HEADER + Container( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 18, + ), + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, // 135deg effect + end: Alignment.bottomRight, + colors: [ + Color(0xFFF0FBFB), // #f0fbfb + Color(0xFFFFFFFF), // #ffffff + ], + stops: [0.0, 0.6], // 0% → 60% + ), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + border: const Border( + bottom: BorderSide(color: Color(0xFFe5e7eb), width: 1), + ), + ), + child: Row( + children: [ + // Container( + // padding: const EdgeInsets.all(10), + // decoration: BoxDecoration( + // color: const Color(0xFF00b5b5), + // borderRadius: BorderRadius.circular(10), + // ), + // child: Text('📝'), + // // const Icon(Icons.edit, color: Color(0xFF0F766E)), + // ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [ + Text( + "Add Endorsement", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + // Text( + // "Create a new endorsement request for an active policy", + // style: TextStyle(fontSize: 11, color: Color(0xFF6b7280),fontWeight: FontWeight.w500), + // ), + ], + ), + const Spacer(), + Container( + width: 34, + height: 34, + // padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Color(0xFFe5e7eb), + style: BorderStyle.solid, + ), + ), + child: InkWell( + onTap: () => Navigator.pop(context), + child: const Icon(Icons.close), + ), + ), + ], + ), + ), + + /// STEPPER + buildStepHeader(), + const SizedBox(height: 15), + + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + Visibility( + visible: !isExternal, + maintainState: true, + maintainAnimation: true, + maintainSize: false, + child: Column( + children: [ + buildSectionTitle("SEARCH POLICY"), + const SizedBox(height: 15), + + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + /// 🔹 VEHICLE SEARCH + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + buildSearchBox( + controller: _vehicleSearchController, + hint: "Search By Vehicle Number", + onChanged: (val) async { + if (val.isNotEmpty) { + await getVehicleListSearchData(val); + } else { + setState( + () => filteredVehicleData.clear(), + ); + } + validateSteps(); + }, + ), + + /// 🔹 Vehicle Results Dropdown + if (filteredVehicleData.isNotEmpty) + Container( + margin: const EdgeInsets.only(top: 6), + height: 150, + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: const Color(0xFFE5E7EB), + ), + borderRadius: BorderRadius.circular( + 12, + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity( + 0.05, + ), + blurRadius: 6, + ), + ], + ), + child: ListView.builder( + padding: EdgeInsets.zero, + itemCount: + filteredVehicleData.length, + itemBuilder: (context, index) { + final vehicle = + filteredVehicleData[index]; + return InkWell( + onTap: () { + setState(() { + controllers['policyNum'] + ?.text = + vehicle['policy_number'] ?? + ''; + _vehicleSearchController + .text = + vehicle['policy_number'] ?? + ''; + filteredVehicleData.clear(); + }); + }, + child: Padding( + padding: + const EdgeInsets.symmetric( + vertical: 8, + horizontal: 12, + ), + child: Text( + vehicle['policy_number'] ?? + '-', + style: _textStyle1, + overflow: + TextOverflow.ellipsis, + ), + ), + ); + }, + ), + ), + ], + ), + ), + + const SizedBox(width: 20), + + /// 🔹 POLICY SEARCH + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + buildSearchBox( + controller: _policySearchController, + hint: "Search By Policy Number", + onChanged: (val) async { + if (val.isNotEmpty) { + await getPolicyListSearchData(val); + } else { + setState( + () => filteredPolicyData.clear(), + ); + } + validateSteps(); + }, + ), + + /// 🔹 Policy Results Dropdown + if (filteredPolicyData.isNotEmpty) + Container( + margin: const EdgeInsets.only(top: 6), + height: 150, + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: const Color(0xFFE5E7EB), + ), + borderRadius: BorderRadius.circular( + 12, + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity( + 0.05, + ), + blurRadius: 6, + ), + ], + ), + child: ListView.builder( + padding: EdgeInsets.zero, + itemCount: + filteredPolicyData.length, + itemBuilder: (context, index) { + final policy = + filteredPolicyData[index]; + return InkWell( + onTap: () { + setState(() { + controllers['policyNum'] + ?.text = + policy['policy_number'] ?? + ''; + _policySearchController + .text = + policy['policy_number'] ?? + ''; + filteredPolicyData.clear(); + }); + }, + child: Padding( + padding: + const EdgeInsets.symmetric( + vertical: 8, + horizontal: 12, + ), + child: Text( + policy['policy_number'] ?? + '-', + style: _textStyle1, + overflow: + TextOverflow.ellipsis, + ), + ), + ); + }, + ), + ), + ], + ), + ), + ], + ), + + const Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + ], + ), + ), + + /// ENDORSEMENT DETAILS + buildSectionTitle("ENDORSEMENT DETAILS"), + const SizedBox(height: 20), + + Row( + children: [ + Expanded(child: buildEndrosPolicyFrom(context)), + const SizedBox(width: 20), + Expanded(child: buildEndrosType(context)), + ], + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded(child: buildPolicyNumber(context)), + const SizedBox(width: 20), + Expanded(child: buildEndorsementNoField(context)), + ], + ), + + const SizedBox(height: 20), + Row( + children: [ + Expanded(child: buildContactPersonField(context)), + const SizedBox(width: 20), + Spacer(), + // Expanded(child: buildPendingDaysField(context)), + ], + ), + + Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + + if (isExternal) ...[ + buildSectionTitle("POLICY INFORMATION"), + const SizedBox(height: 20), + Row( + children: [ + Expanded(child: buildRegNoField(context)), + const SizedBox(width: 20), + Expanded(child: buildBrokerDropdown(context)), + // Expanded(child: buildPendingDaysField(context)), + ], + ), + const SizedBox(height: 25), + Row( + children: [ + Expanded(child: buildPolicyStartDate(context)), + SizedBox(width: 20), + Expanded(child: buildPolicyEndDate(context)), + ], + ), + const SizedBox(height: 25), + Row( + children: [ + Expanded(child: buildInsurerDropdown(context)), + const SizedBox(width: 20), + Expanded(child: buildInsuredNameField(context)), + ], + ), + + Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + ], + + /// UPLOAD & REMARKS + buildSectionTitle("UPLOAD & REMARKS"), + const SizedBox(height: 20), + + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: buildUploadBox()), + const SizedBox(width: 25), + Expanded(child: buildEndrosRemarks(context)), + ], + ), + + Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + + /// Financial & Status + buildSectionTitle("Financial & Status"), + const SizedBox(height: 20), + + /// FINANCIAL + Row( + children: [ + Expanded(child: buildFinancialToggle()), + const SizedBox(width: 20), + Expanded( + child: showFinancialFields + ? buildPaymentModeDropdown() + : const Spacer(), // 👈 match dropdown total height + ), + ], + ), + + if (showFinancialFields) ...[ + const SizedBox(height: 20), + Row( + children: [ + Expanded(child: buildPremiumField(context)), + const SizedBox(width: 20), + Expanded(child: buildCommissionField(context)), + ], + ), + ], + + const SizedBox(height: 20), + + // Row( + // children: [ + // Expanded(child: buildLifecycleStatus()), + // const SizedBox(width: 25), + // Expanded(child: buildVerificationStatus()), + // ], + // ), + + /// SAVE BUTTON + // Align( + // alignment: Alignment.centerRight, + // child: ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: const Color(0xFF0F766E), + // padding: const EdgeInsets.symmetric( + // horizontal: 40, + // vertical: 14, + // ), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(25), + // ), + // ), + // onPressed: () { + // if (!_formKeyEndrosment.currentState!.validate()) return; + // final dataSet = endrosmentDetails(); + // createUserData(dataSet); + // }, + // child: const Text( + // "Save Endorsement", + // style: TextStyle(fontSize: 13), + // ), + // ), + // ), + ], + ), + ), + ), + + SizedBox(height: 20), + + Container( + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 18, + ), + decoration: const BoxDecoration( + border: Border(top: BorderSide(color: Color(0xFFE5E7EB))), + ), + child: Row( + children: [ + /// Left Side - Required text + const Text( + "* Required fields", + style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)), + ), + + const Spacer(), + + /// Cancel Button + Container( + height: 44, + margin: const EdgeInsets.only(right: 14), + child: OutlinedButton( + onPressed: () => Navigator.pop(context), + style: OutlinedButton.styleFrom( + backgroundColor: Colors.white, + side: const BorderSide(color: Color(0xFFE5E7EB)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.symmetric(horizontal: 24), + ), + child: const Text( + "Cancel", + style: TextStyle( + fontSize: 13, + color: Color(0xFF374151), + fontWeight: FontWeight.w400, + ), + ), + ), + ), + + /// Save Button + Container( + height: 44, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + gradient: const LinearGradient( + colors: [Color(0xFF14B8A6), Color(0xFF0F766E)], + ), + boxShadow: [ + BoxShadow( + color: const Color(0xFF0F766E).withOpacity(0.25), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: ElevatedButton( + onPressed: isSubmitLoading + ? null // 🚫 Disable while loading + : () { + if (!_formKeyEndrosment.currentState! + .validate()) + return; + + final dataSet = endrosmentDetails(); + createUserData(dataSet); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + padding: const EdgeInsets.symmetric(horizontal: 26), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + + /// 👇 Dynamic Child + child: isSubmitLoading + ? const SizedBox( + height: 18, + width: 18, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : Row( + mainAxisSize: MainAxisSize.min, + children: const [ + Icon(Icons.save, size: 18), + SizedBox(width: 8), + Text( + "Save Endorsement", + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } + + Widget buildStepHeader() { + Widget step(String title, int number, bool completed, bool active) { + return Row( + children: [ + stepCircle(number, completed, active), + const SizedBox(width: 5), + Text( + title, + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: completed || active + ? const Color(0xFF008f8f) + : const Color(0xFF9CA3AF), + ), + ), + ], + ); + } + + Widget arrow() { + return const Padding( + padding: EdgeInsets.symmetric(horizontal: 14), + child: Icon(Icons.chevron_right, size: 18, color: Color(0xFFD1D5DB)), + ); + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), + decoration: const BoxDecoration( + color: Color(0xFFfafbfc), // light grey background bar + // borderRadius: BorderRadius.only( + // topLeft: Radius.circular(12), + // topRight: Radius.circular(12), + // ), + border: const Border( + bottom: BorderSide(color: Color(0xFFe5e7eb), width: 1), + ), + ), + child: Row( + children: [ + if (!isExternal) ...[ + step("Search Policy", 1, step1Completed, currentStep == 1), + arrow(), + ], + step("Endorsement Details", 2, step2Completed, currentStep == 2), + arrow(), + step("Upload & Remarks", 3, step3Completed, currentStep == 3), + arrow(), + step("Status & Save", 4, step4Completed, currentStep == 4), + ], + ), + ); + } + + Widget stepCircle(int number, bool completed, bool active) { + if (completed) { + return Container( + width: 28, + height: 28, + decoration: const BoxDecoration( + color: Color(0xFF16A34A), + shape: BoxShape.circle, + ), + child: const Icon(Icons.check, size: 16, color: Colors.white), + ); + } + + if (active) { + return Container( + width: 32, + height: 32, + decoration: const BoxDecoration( + color: Color(0xFFd4edef), // outer grey ring + shape: BoxShape.circle, + ), + child: Center( + child: Container( + width: 26, + height: 26, + decoration: const BoxDecoration( + color: Color(0xFF00b5b5), // teal inner + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + number.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 11, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ); + } + + return Container( + width: 28, + height: 28, + decoration: const BoxDecoration( + color: Color(0xFFE5E7EB), + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + number.toString(), + style: const TextStyle( + color: Color(0xFF6B7280), + fontSize: 11, + fontWeight: FontWeight.w500, + ), + ), + ); + } + + Widget buildSearchBox({ + required TextEditingController controller, + required String hint, + required Function(String) onChanged, + }) { + final FocusNode focusNode = FocusNode(); + bool isFocused = false; + + return StatefulBuilder( + builder: (context, setStateSB) { + focusNode.addListener(() { + setStateSB(() { + isFocused = focusNode.hasFocus; + }); + }); + + return Container( + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: isFocused + ? const Color(0xFF008f8f) // teal border + : const Color(0xFFE5E7EB), + width: 1.5, + ), + boxShadow: isFocused + ? [ + BoxShadow( + color: const Color(0xFF008f8f).withOpacity(0.15), + blurRadius: 8, + spreadRadius: 1, + ), + ] + : [], + ), + child: Row( + children: [ + Expanded( + child: TextField( + focusNode: focusNode, + controller: controller, + onChanged: onChanged, + style: const TextStyle( + fontSize: 13, + color: Color(0xFF374151), + ), + decoration: InputDecoration( + hintText: hint, + hintStyle: const TextStyle( + color: Color(0xFF9CA3AF), + fontSize: 13, + ), + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 14, + vertical: 15, + ), + ), + ), + ), + + /// Search Icon Button + Container( + margin: const EdgeInsets.only(right: 8), + width: 30, + height: 30, + decoration: BoxDecoration( + color: const Color(0xFF008f8f), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon(Icons.search, color: Colors.white, size: 18), + ), + ], + ), + ); + }, + ); + } + + Widget buildUploadBox() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + /// Label Row + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + Text( + "Upload Document", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + Text( + "PDF / JPG / PNG", + style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)), + ), + ], + ), + const SizedBox(height: 10), + + /// Upload Container + GestureDetector( + onTap: () async { + FilePickerResult? result = await FilePicker.platform.pickFiles(); + + if (result != null) { + setState(() { + docUploadedEndorsFile = result.files.first; + }); + } + }, + child: Container( + height: 160, + decoration: BoxDecoration( + color: const Color(0xFFF8FAFC), + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: const Color(0xFF0F766E), + width: 1.5, + style: BorderStyle.solid, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.attach_file, + size: 34, + color: Color(0xFF9CA3AF), + ), + const SizedBox(height: 12), + Text( + docUploadedEndorsFile != null + ? docUploadedEndorsFile!.name + : "Click to upload or drag & drop", + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w400, + color: Color(0xFF374151), + ), + ), + const SizedBox(height: 6), + const Text( + "Endorsement document, policy copy", + style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)), + ), + const SizedBox(height: 10), + + /// File Type Chips + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + buildFileChip("PDF"), + const SizedBox(width: 8), + buildFileChip("JPG"), + const SizedBox(width: 8), + buildFileChip("PNG"), + const SizedBox(width: 8), + buildFileChip("Max 5MB"), + ], + ), + ], + ), + ), + ), + ], + ); + } + + Widget buildFileChip(String text) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: const Color(0xFFE5E7EB), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + text, + style: const TextStyle(fontSize: 11, color: Color(0xFF374151)), + ), + ); + } + + Widget buildSectionTitle(String title) { + return Row( + children: [ + Container(width: 3, height: 14, color: Color(0xFF00b5b5)), + const SizedBox(width: 8), + Text( + title, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 11, + letterSpacing: 2, + color: Color(0xFF6b7280), + ), + ), + ], + ); + } + + Widget buildPolicyNumber(context) { + return buildCommonTextField( + label: "Policy Number", + controller: controllers['policyNum']!, + isRequired: true, + readOnly: isPolicyNumberReadOnly, + isFocused: isPolicyNumberFocused, + onFocusChanged: (val) { + setState(() { + isPolicyNumberFocused = val; + }); + }, + ); + } + + //------------------------- Endrosment Part ----------------------------------- + + Widget buildEndrosRemarks(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Remarks", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const SizedBox(height: 10), + + Container( + height: 160, // 👈 textarea height + decoration: BoxDecoration( + color: const Color(0xFFF9FAFB), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFFE5E7EB)), + ), + child: TextFormField( + controller: controllers['remarks'], + keyboardType: TextInputType.multiline, + maxLines: null, // allow unlimited lines + textAlignVertical: TextAlignVertical.top, + style: const TextStyle(fontSize: 13, color: Color(0xFF374151)), + decoration: const InputDecoration( + hintText: + "Describe the reason for this endorsement request, changes being made, or any additional instructions...", + hintStyle: TextStyle(fontSize: 11, color: Color(0xFF9CA3AF)), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + // validator: (value) => + // Validators.requiredField(value, "remarks"), + ), + ), + ], + ); + } + + Widget buildPolicyStartDate(context) { + return buildDateField( + context, + "Policy Start Date", + policyStartController, + isStartDateFocused, + (val) => setState(() => isStartDateFocused = val), + ); + } + + Widget buildPolicyEndDate(context) { + return buildDateField( + context, + "Policy End Date", + policyEndController, + isEndDateFocused, + (val) => setState(() => isEndDateFocused = val), + ); + } + + Widget buildDateField( + BuildContext context, + String label, + TextEditingController controller, + bool isFocused, + Function(bool) onFocusChanged, + ) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: '$label *', + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + children: label.contains("*") + ? const [ + TextSpan( + text: " *", + style: TextStyle(color: Colors.red), + ), + ] + : [], + ), + ), + const SizedBox(height: 8), + + AnimatedContainer( + duration: const Duration(milliseconds: 180), + constraints: const BoxConstraints(minHeight: 40), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(14), + ), + child: GestureDetector( + onTap: () async { + onFocusChanged(true); + + DateTime? picked = await showDatePicker( + context: context, + firstDate: DateTime(2000), + lastDate: DateTime.now(), + initialDate: DateTime.now(), + ); + + onFocusChanged(false); + + if (picked != null) { + controller.text = + "${picked.day.toString().padLeft(2, '0')}-" + "${picked.month.toString().padLeft(2, '0')}-" + "${picked.year}"; + } + }, + child: AbsorbPointer( + child: TextFormField( + controller: controller, + validator: (value) { + if (isExternal && (value == null || value.isEmpty)) { + return "$label is required"; + } + return null; + }, + readOnly: true, + style: const TextStyle(fontSize: 13, color: Color(0xFF374151)), + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + isDense: true, // ⭐ important + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Colors.red, + width: 1.5, + ), + ), + + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Colors.red, + width: 1.5, + ), + ), + + helperText: " ", + helperStyle: const TextStyle(height: 0.8), + + errorStyle: const TextStyle( + fontSize: 11, + height: 1.3, + ), + + suffixIcon: const Icon( + Icons.calendar_today_outlined, + size: 18, + color: Color(0xFF6B7280), + ), + ), + ), + ), + ), + ), + ], + ); + } + + Widget buildRegNoField(context) { + return buildCommonTextField( + label: "Vehicle Number", + controller: regNoController, + isRequired: isExternal, + isFocused: isRegNoFocused, + onFocusChanged: (val) { + setState(() => isRegNoFocused = val); + }, + ); + } + + Widget buildInsuredNameField(context) { + return buildCommonTextField( + label: "Insured Name", + controller: insuredNameController, + isRequired: isExternal, + isFocused: isInsuredNameFocused, + onFocusChanged: (val) { + setState(() => isInsuredNameFocused = val); + }, + ); + } + + Widget buildEndorsementNoField(context) { + return buildCommonTextField( + label: "Endorsement No", + controller: endorsementNoController, + isRequired: false, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9]')), + ], + isFocused: isEndorsementNoFocused, + onFocusChanged: (val) { + setState(() => isEndorsementNoFocused = val); + }, + ); + } + + Widget buildContactPersonField(context) { + return buildCommonTextField( + label: "Contact Person", + controller: contactPersonController, + isRequired: false, + isFocused: isContactPersonFocused, + onFocusChanged: (val) { + setState(() => isContactPersonFocused = val); + }, + ); + } + + // Widget buildPendingDaysField(context) { + // return buildCommonTextField( + // label: "Pending Days", + // controller: pendingDaysController, + // isRequired: isInternal, + // keyboardType: TextInputType.number, + // isFocused: isPendingDaysFocused, + // onFocusChanged: (val) { + // setState(() => isPendingDaysFocused = val); + // }, + // ); + // } + + Widget buildPremiumField(context) { + return buildCommonTextField( + label: "Endorsement Premium", + controller: premiumController, + isRequired: showFinancialFields, + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + isFocused: isPremiumFocused, + onFocusChanged: (val) { + setState(() => isPremiumFocused = val); + }, + ); + } + + Widget buildCommissionField(context) { + return buildCommonTextField( + label: "Commission Amount", + controller: commissionController, + isRequired: showFinancialFields, + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + isFocused: isCommissionFocused, + onFocusChanged: (val) { + setState(() => isCommissionFocused = val); + }, + ); + } + + Widget buildCommonTextField({ + required String label, + required TextEditingController controller, + required bool isRequired, + bool readOnly = false, + TextInputType keyboardType = TextInputType.text, + List? inputFormatters, + required bool isFocused, + required Function(bool) onFocusChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: label, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + children: isRequired + ? const [ + TextSpan( + text: " *", + style: TextStyle(color: Colors.red), + ), + ] + : [], + ), + ), + const SizedBox(height: 8), + TextFormField( + controller: controller, + readOnly: readOnly, + keyboardType: keyboardType, + inputFormatters: inputFormatters, + validator: (value) { + if (isRequired && (value == null || value.trim().isEmpty)) { + return "$label is required"; + } + return null; + }, + style: const TextStyle(fontSize: 13, color: Color(0xFF374151)), + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + + isDense: true, // ⭐ important + + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, // ⭐ reduce vertical padding + ), + + helperText: " ", // 🔥 IMPORTANT FIX + helperStyle: const TextStyle(height: 0.8), + + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + ), + ), + // AnimatedContainer( + // duration: const Duration(milliseconds: 180), + // constraints: const BoxConstraints( + // minHeight: 40, + // ), + // decoration: BoxDecoration( + // color: isFocused ? Colors.white : const Color(0xFFF9FAFB), + // borderRadius: BorderRadius.circular(14), + // border: Border.all( + // color: isFocused + // ? const Color(0xFF0F766E) + // : const Color(0xFFE5E7EB), + // width: 1.5, + // ), + // boxShadow: isFocused + // ? [ + // BoxShadow( + // color: Color(0xFF0F766E).withOpacity(0.12), + // blurRadius: 6, + // spreadRadius: 1, + // ) + // ] + // : [], + // ), + // child: Focus( + // onFocusChange: onFocusChanged, + // child: TextFormField( + // controller: controller, + // readOnly: readOnly, + // validator: (value) { + // if (isRequired) { + // if (value == null || value.trim().isEmpty) { + // return "$label is required"; + // } + // } + // return null; + // }, + // keyboardType: keyboardType, + // style: const TextStyle( + // fontSize: 13, + // color: Color(0xFF374151), + // ), + // decoration: const InputDecoration( + // border: InputBorder.none, + // isDense: true, + // contentPadding: const EdgeInsets.symmetric( + // horizontal: 16, + // vertical: 10, + // ), + // ), + // ), + // ), + // ), + ], + ); + } + + Widget buildFinancialToggle() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text( + "Financial Status", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const Text(" *", style: TextStyle(color: Colors.red)), + const SizedBox(width: 12), + Expanded( + child: const Text( + "Additional premium?", + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)), + ), + ), + ], + ), + const SizedBox(height: 8), + + /// Segmented Container + Container( + height: 40, + decoration: BoxDecoration( + color: const Color(0xFFF3F4F6), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFFE5E7EB)), + ), + child: Row( + children: [ + /// YES BUTTON + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + financialType = "Yes"; + showFinancialFields = true; + }); + }, + child: Container( + decoration: BoxDecoration( + color: financialType == "Yes" + ? const Color(0xFF16a34a) + : Colors.transparent, + borderRadius: BorderRadius.circular(14), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.check, + size: 16, + color: financialType == "Yes" + ? const Color(0xFFFFFFFF) + : const Color(0xFF9CA3AF), + ), + const SizedBox(width: 6), + Text( + "Yes", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + color: financialType == "Yes" + ? const Color(0xFFFFFFFF) + : const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ), + ), + + /// Divider + Container(width: 1, color: const Color(0xFFE5E7EB)), + + /// NO BUTTON + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + financialType = "No"; + showFinancialFields = false; + }); + }, + child: Container( + decoration: BoxDecoration( + color: financialType == "No" + ? const Color(0xFFE5E7EB) + : Colors.transparent, + borderRadius: BorderRadius.circular(14), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.close, + size: 16, + color: financialType == "No" + ? const Color(0xFF374151) + : const Color(0xFF9CA3AF), + ), + const SizedBox(width: 6), + Text( + "No", + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + color: financialType == "No" + ? const Color(0xFF374151) + : const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + /// ⭐ IMPORTANT: reserve space like TextFormField + const SizedBox(height: 20), + ], + ); + } + + Widget buildSegmentedStatus({ + required String title, + required List> options, + required String selectedValue, + required Function(String) onChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + title, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const Text(" *", style: TextStyle(color: Colors.red)), + ], + ), + const SizedBox(height: 12), + + Row( + children: options.map((option) { + final bool isSelected = selectedValue == option["value"]; + + return Expanded( + child: GestureDetector( + onTap: () => onChanged(option["value"]), + child: Container( + height: 40, + margin: const EdgeInsets.only(right: 12), + decoration: BoxDecoration( + color: isSelected + ? option["selectedColor"] + : const Color(0xFFF3F4F6), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: isSelected + ? option["borderColor"] ?? option["selectedColor"] + : const Color(0xFFE5E7EB), + ), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + option["icon"], + size: 16, + color: isSelected + ? option["textColor"] ?? const Color(0xFF111827) + : const Color(0xFF6B7280), + ), + const SizedBox(width: 6), + Text( + option["label"], + style: TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + color: isSelected + ? option["textColor"] ?? const Color(0xFF111827) + : const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ), + ); + }).toList(), + ), + ], + ); + } + + Widget buildLifecycleStatus() { + return buildSegmentedStatus( + title: "Lifecycle Status", + selectedValue: lifecycleStatus, + options: [ + { + "label": "Open", + "value": "Open", + "icon": Icons.circle, + "selectedColor": const Color(0xFFfef3c7), // 🔥 Yellow + "textColor": const Color(0xFF92400E), + }, + { + "label": "Closed", + "value": "Closed", + "icon": Icons.circle, + "selectedColor": const Color(0xFFdcfce7A), // Green light + "textColor": const Color(0xFF065F46), + }, + ], + onChanged: (val) { + setState(() { + lifecycleStatus = val; + }); + }, + ); + } + + Widget buildVerificationStatus() { + return buildSegmentedStatus( + title: "Verification Status", + selectedValue: verificationStatus, + options: [ + { + "label": "To Verify", + "value": "To Verify", + "icon": Icons.diamond, + "selectedColor": const Color(0xFF93C5FD), // 🔥 Blue + "textColor": const Color(0xFF1E40AF), + }, + { + "label": "Verified", + "value": "Verified", + "icon": Icons.check_box, + "selectedColor": const Color(0xFFD1FAE5), + "textColor": const Color(0xFF065F46), + }, + ], + onChanged: (val) { + setState(() { + verificationStatus = val; + }); + }, + ); + } + + Widget buildCommonDropdown({ + required String label, + required String hintText, + required List> items, + required Map? selectedItem, + required String Function(Map) itemAsString, + required Function(Map?) onChanged, + required bool isRequired, + required bool isFocused, + required Function(bool) onFocusChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: label, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + children: isRequired + ? const [ + TextSpan( + text: " *", + style: TextStyle(color: Colors.red), + ), + ] + : [], + ), + ), + const SizedBox(height: 8), + + Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(14)), + child: DropdownSearch>( + selectedItem: selectedItem, + items: (f, i) => items, + itemAsString: itemAsString, + compareFn: (item, s) => item['id'].toString() == s['id'].toString(), + onChanged: onChanged, + + validator: (value) { + if (isRequired && value == null) { + return "$label is required"; + } + return null; + }, + + onBeforePopupOpening: (val) async { + onFocusChanged(true); + return true; + }, + + popupProps: PopupProps.menu( + onDismissed: () { + onFocusChanged(false); + }, + showSearchBox: true, + ), + + decoratorProps: DropDownDecoratorProps( + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + + isDense: true, // ⭐ important + + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + + helperText: " ", // 🔥 IMPORTANT FIX + helperStyle: const TextStyle(height: 0.8), + + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + ), + ), + ), + ), + ], + ); + } + + Widget buildEndrosType(context) { + Map? selectedItem = filteredEndrosmentData.firstWhere( + (item) => item['id'].toString() == selectedEndorsement, + orElse: () => {}, + ); + + return buildCommonDropdown( + label: "Endorsement Type", + hintText: "Select Endorsement Type", + isRequired: true, + items: filteredEndrosmentData, + selectedItem: selectedItem.isNotEmpty ? selectedItem : null, + isFocused: isEndorsementTypeFocused, + onFocusChanged: (val) { + setState(() { + isEndorsementTypeFocused = val; + }); + }, + itemAsString: (val) => val['endorsement_type'].toString(), + onChanged: (val) { + if (val != null) { + setState(() { + selectedEndorsement = val['id']; + }); + validateSteps(); + } + }, + ); + } + + Widget buildEndrosPolicyFrom(context) { + Map? selectedItem = + policyFromOptions + .where( + (item) => item['policy_from'] == selectedEndrosementPolicyFrom, + ) + .isNotEmpty + ? policyFromOptions.firstWhere( + (item) => item['policy_from'] == selectedEndrosementPolicyFrom, + ) + : null; + + return buildCommonDropdown( + label: "Policy From", + hintText: "Select Policy From", + isRequired: true, + items: policyFromOptions, + selectedItem: selectedItem, + itemAsString: (val) => val['policy_from'], + isFocused: isPolicyFromFocused, + onFocusChanged: (val) { + setState(() { + isPolicyFromFocused = val; + }); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedEndrosementPolicyFrom = val['policy_from']; + + isInternal = selectedEndrosementPolicyFrom == "Internal"; + isExternal = selectedEndrosementPolicyFrom == "External"; + + /// 🔥 POLICY NUMBER LOGIC + if (isExternal) { + controllers['policyNum']!.clear(); + _vehicleSearchController.clear(); + _policySearchController.clear(); + filteredVehicleData.clear(); + filteredPolicyData.clear(); + controllers['policyNum']!.clear(); + isPolicyNumberReadOnly = false; + } else { + isPolicyNumberReadOnly = true; + } + + // 🔥 CLEAR FIELDS WHEN SWITCHING + if (isInternal) { + selectedInsurer = null; + selectedBroker = null; + selectedPaymentModeId = null; + + insuredNameController.clear(); + regNoController.clear(); + policyStartController.clear(); + policyEndController.clear(); + } + + if (isExternal) { + endorsementNoController.clear(); + contactPersonController.clear(); + // pendingDaysController.clear(); + } + + showFinancialFields = financialType == "Yes"; + validateSteps(); + }); + } + }, + ); + } + + Widget buildInsurerDropdown(context) { + Map? selectedItem = + insurerList + .where( + (item) => item['id']?.toString() == selectedInsurer?.toString(), + ) + .isNotEmpty + ? insurerList.firstWhere( + (item) => item['id']?.toString() == selectedInsurer?.toString(), + ) + : null; + + return buildCommonDropdown( + label: "Insurer", + hintText: "Select Insurer", + isRequired: isExternal, + items: insurerList, + selectedItem: selectedItem, + itemAsString: (val) => val['short_name'] ?? val['name'] ?? "", + isFocused: isInsurerFocused, + onFocusChanged: (val) { + setState(() => isInsurerFocused = val); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedInsurer = val['id']; + }); + validateSteps(); + } + }, + ); + } + + Widget buildBrokerDropdown(context) { + Map? selectedItem = + brokerList + .where( + (item) => item['id']?.toString() == selectedBroker?.toString(), + ) + .isNotEmpty + ? brokerList.firstWhere( + (item) => item['id']?.toString() == selectedBroker?.toString(), + ) + : null; + + return buildCommonDropdown( + label: "Broker", + hintText: "Select Broker", + isRequired: isExternal, + items: brokerList, + selectedItem: selectedItem, + itemAsString: (val) => val['short_name'] ?? val['name'] ?? "", + isFocused: isBrokerFocused, + onFocusChanged: (val) { + setState(() => isBrokerFocused = val); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedBroker = val['id']; + }); + } + }, + ); + } + + Widget buildPaymentModeDropdown() { + Map? selectedItem = + getPaymentModeData + .where( + (item) => + item['id']?.toString() == selectedPaymentModeId?.toString(), + ) + .isNotEmpty + ? getPaymentModeData.firstWhere( + (item) => + item['id']?.toString() == selectedPaymentModeId?.toString(), + ) + : null; + + return buildCommonDropdown( + label: "Payment Mode", + hintText: "Select Payment Mode", + isRequired: true, + items: getPaymentModeData, + selectedItem: selectedItem, + + /// 🔥 IMPORTANT FIX HERE + itemAsString: (val) => val['value'] ?? "", + + isFocused: isPaymentModeFocused, + onFocusChanged: (val) { + setState(() => isPaymentModeFocused = val); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedPaymentModeId = val['id'].toString(); + }); + validateSteps(); + } + }, + ); + } + + // ------------------- STyle --------------------------------- + + static final TextStyle _textStyle = TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + ); + static final TextStyle _textStyle1 = TextStyle( + fontSize: 9, + fontWeight: FontWeight.w300, + ); +} diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart new file mode 100644 index 0000000..21c1e1c --- /dev/null +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/endorsomentUpdateValidation.dart @@ -0,0 +1,3025 @@ +import 'dart:convert'; + +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/screens/staff/policy/policyPdf.dart'; +import 'package:pdf_render/pdf_render_widgets.dart'; +import 'package:syncfusion_flutter_pdfviewer/pdfviewer.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 '../../../providers/manager_provider.dart'; + +import '../../../providers/userRoleProvider.dart'; +import '../../../themes/indicators/customizd_file_upload.dart'; +import '../../../themes/indicators/input_field_decoration.dart'; +import '../../../screens/staff/policy/loadNetworkPdfBytes.dart'; +import 'dart:typed_data'; + +import 'package:flutter/services.dart'; + +import '../../../themes/indicators/search_field_theme.dart'; +import '../../../themes/indicators/text_field_theme.dart'; + +final digitsOnlyFormatter = [FilteringTextInputFormatter.digitsOnly]; + +final decimalFormatter = [ + FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}$')), +]; + +class endorsomentValidation extends ConsumerStatefulWidget { + final String title; + final dynamic userId; + final dynamic managerId; + final dynamic role; + final dynamic item; + final void Function(String value) onSubmit; + + const endorsomentValidation({ + super.key, + required this.title, + required this.onSubmit, + required this.userId, + required this.managerId, + required this.item, + required this.role, + }); + @override + ConsumerState createState() => + _endorsomentValidationState(); +} + +class _endorsomentValidationState extends ConsumerState { + String? _cachedPdfUrl; + String? pdfUrl; // full file path from API + late ApiService apiService; + bool isLoading = false; + bool isSubmitLoading = false; + + dynamic userId; + dynamic roleId; + dynamic managerId; + + String lifecycleStatus = "Open"; // default + String verificationStatus = "To Verify"; // default + + late TextEditingController controller; + Map controllers = {}; + + String? _token; + String? selectedClaimFileNames; + String? selectedEndorsement; + String? selectedEndrosementPolicyFrom; + String? selectedFileNames; + + String? selectedPaymentModeId; + + bool isPolicyFromFocused = false; + bool isEndorsementTypeFocused = false; + bool isInsurerFocused = false; + bool isBrokerFocused = false; + bool isPolicyNumberFocused = false; + + bool isRegNoFocused = false; + bool isInsuredNameFocused = false; + bool isEndorsementNoFocused = false; + bool isContactPersonFocused = false; + bool isPendingDaysFocused = false; + bool isPremiumFocused = false; + bool isCommissionFocused = false; + bool isStartDateFocused = false; + bool isEndDateFocused = false; + bool isPaymentModeFocused = false; + + String policyFrom = ""; + String financialOrNonFinancial = ""; + + bool isPolicyNumberReadOnly = true; + + PlatformFile? uploadedFile; + + final _formKeyClaims = GlobalKey(); + final _formKeyEndrosment = GlobalKey(); + final GlobalKey>> dropDownKey = + GlobalKey>>(); + final GlobalKey>> + dropDownKeyEndorsement = + GlobalKey>>(); + + final TextEditingController _vehicleSearchController = + TextEditingController(); + final TextEditingController _policySearchController = TextEditingController(); + + /// Controllers + final TextEditingController policyNumber = TextEditingController(); + final TextEditingController endorsementDescription = TextEditingController(); + final TextEditingController contactPerson = TextEditingController(); + final TextEditingController pendingDays = TextEditingController(); + final TextEditingController premium = TextEditingController(); + final TextEditingController commission = TextEditingController(); + // 🔹 NEW CONTROLLERS + final TextEditingController regNoController = TextEditingController(); + final TextEditingController insuredNameController = TextEditingController(); + final TextEditingController endorsementNoController = TextEditingController(); + final TextEditingController contactPersonController = TextEditingController(); + // final TextEditingController pendingDaysController = TextEditingController(); + final TextEditingController premiumController = TextEditingController(); + final TextEditingController commissionController = TextEditingController(); + final TextEditingController policyStartController = TextEditingController(); + final TextEditingController policyEndController = TextEditingController(); + + // 🔹 DROPDOWN VALUES + String? selectedInsurer; + String? selectedBroker; + String? selectedEndorsementNo; + // String? selectedInsuredName; + String financialType = "Yes"; + + // 🔹 LISTS + List> insurerList = []; + List> brokerList = []; + List> endorsementNoList = []; + List> insuredNameList = []; + + PlatformFile? docUploadedFile; + PlatformFile? docUploadedEndorsFile; + + List> getEndrosmentType = []; + List> filteredEndrosmentData = []; + + List> getPolicyListData = []; + List> originalPolicyData = []; + List> filteredPolicyData = []; + + List> getVehicleListData = []; + List> originalVehicleData = []; + List> filteredVehicleData = []; + + List> getPolicyData = []; + List> originalData = []; + List> filteredData = []; + + List> getPaymentModeData = []; + List> filteredPaymentModeData = []; + + final List> policyFromOptions = [ + {"policy_from": "Internal"}, + {"policy_from": "External"}, + ]; + + bool isInternal = false; + bool isExternal = false; + bool showFinancialFields = true; + + final GlobalKey _pdfViewerKey = GlobalKey(); + + Map endrosmentDetails() { + Map data = { + "policy_number": controllers["policyNum"]?.text, + "endorsement_type": selectedEndorsement, + "policy_from": selectedEndrosementPolicyFrom, + "manager_id": widget.managerId, + "updated_by": widget.userId, + "id": widget.item?['id'], + "endorsement_description": controllers["remarks"]?.text, + "status": lifecycleStatus, + }; + + if (isInternal) { + data.addAll({ + "endorsement_no": endorsementNoController.text, + "contact_person": contactPersonController.text, + // "pending_days": pendingDaysController.text, + "financia_or_non_financial": financialType, + "payment_mode_id": selectedPaymentModeId, + }); + + if (showFinancialFields) { + data.addAll({ + "endorsement_premium": premiumController.text, + "commission_amount": commissionController.text, + }); + } + } + + if (isExternal) { + data.addAll({ + "endorsement_no": endorsementNoController.text, + "contact_person": contactPersonController.text, + // "pending_days": pendingDaysController.text, + "financia_or_non_financial": financialType, + + "insurer_id": selectedInsurer, + "insured_name": insuredNameController.text, + "policy_start_date": policyStartController.text, + "policy_end_date": policyEndController.text, + "reg_no": regNoController.text, + "broker_id": selectedBroker, + "endorsement_premium": premiumController.text, + "commission_amount": commissionController.text, + "payment_mode_id": selectedPaymentModeId, + }); + } + + return data; + } + + bool showExistingFile = false; + String? existingFileName; + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + + existingFileName = widget.item?['endorsement_file_name']; + + showExistingFile = + existingFileName != null && existingFileName.toString().isNotEmpty; + + // ✅ INITIALIZE CONTROLLERS MAP + controllers = { + 'policyNum': TextEditingController(), + 'remarks': TextEditingController(), + 'startDate': TextEditingController(), + 'endDate': TextEditingController(), + }; + + Future.microtask(() async { + managerId = ref.read(managerIdProvider); + roleId = ref.read(userRoleProvider); + userId = ref.read(userIdProvider); + + if (userId != null) { + await getStaffList(managerId, userId, roleId); + } + }); + + WidgetsBinding.instance.addPostFrameCallback((_) { + setEditValues(); + }); + + _initializeToken(); + getPolicyFilePath(); + getEnroementType(); + getBroker(); + getInsurerDetails(); + getPaymentMode(); + } + + @override + void dispose() { + _vehicleSearchController.dispose(); + _policySearchController.dispose(); + + for (var controller in controllers.values) { + controller.dispose(); + } + + super.dispose(); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + void setEditValues() { + final item = widget.item; + + if (item == null) return; + final policyFromValue = item['policy_from']?.toString() ?? ''; + + setState(() { + controllers['policyNum']?.text = item['policy_number'] ?? ''; + controllers['remarks']?.text = item['endorsement_description'] ?? ''; + + endorsementNoController.text = item['endorsement_no'] ?? ''; + contactPersonController.text = item['contact_person'] ?? ''; + // pendingDaysController.text = item['pending_days']?.toString() ?? ''; + premiumController.text = item['endorsement_premium']?.toString() ?? ''; + commissionController.text = item['commission_amount']?.toString() ?? ''; + selectedPaymentModeId = item['payment_mode_id']?.toString(); + + insuredNameController.text = item['insured_name'] ?? ''; + regNoController.text = item['reg_no'] ?? ''; + policyStartController.text = item['policy_start_date'] ?? ''; + policyEndController.text = item['policy_end_date'] ?? ''; + + selectedInsurer = item['insurer_id']?.toString(); + selectedBroker = item['broker_id']?.toString(); + selectedEndorsement = item['endorsement_type']?.toString(); + selectedEndrosementPolicyFrom = item['policy_from']; + lifecycleStatus = item['status']; + + financialType = item['financia_or_non_financial'] ?? "Yes"; + + // 🔥 IMPORTANT PART + isInternal = policyFromValue == "Internal"; + isExternal = policyFromValue == "External"; + + showFinancialFields = financialType == "Yes"; + }); + } + + Future getEnroementType() async { + print('Insurers called'); + + 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; + }); + } + } + + Future getPaymentMode() async { + print('getPaymentMode called'); + + try { + final response = await apiService.fetchMasterDropDown('PaymentMode'); + + if (response['status'] == 200) { + print('getPaymentModeData - ${response['data']}'); + setState(() { + getPaymentModeData = List>.from( + response['data'], + ); + print('API Data - $getPaymentModeData'); + + filteredPaymentModeData = List.from(getPaymentModeData); + print('originalData - $filteredPaymentModeData'); + }); + } else { + getPaymentModeData = []; + filteredPaymentModeData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + // Get Broker List + Future getBroker() async { + print('getBroker called'); + + try { + final response = await apiService.fetchMasterDropDown('Broker'); + + if (response['status'] == 200) { + print('getBroker - ${response['data']}'); + setState(() { + brokerList = List>.from(response['data']); + print('API Data - $brokerList'); + + // filteredBrokerData = List.from(getBrokerData); + // print('originalData - $filteredBrokerData'); + }); + } else { + brokerList = []; + // filteredBrokerData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getInsurerDetails() async { + try { + final response = await apiService.fetchMasterDropDown('Insurers'); + + print("***999999999999999999*********** $response"); + + if (response['status'] == 200) { + print('getInsurerDetails - ${response['data']}'); + + setState(() { + insurerList = List>.from(response['data']); + + // filteredInsurerData = + // List>.from(getInsurerDetailsData); + // + // print("Filtered Insurer Data: $filteredInsurerData"); + }); + } else { + setState(() { + insurerList = []; + // filteredInsurerData = []; + }); + } + } catch (e) { + print('Error: $e'); + } + } + + Future getPolicyListSearchData(String val) async { + try { + final response = await apiService.fetchPolicySearch(val); + + if (response['status'] == 'success' && response['data'] != null) { + final dataList = List>.from(response['data']); + setState(() { + getPolicyListData = dataList; + originalPolicyData = dataList; + filteredPolicyData = List.from(originalPolicyData); + }); + } else { + setState(() { + getPolicyListData = []; + originalPolicyData = []; + filteredPolicyData = []; + }); + } + } catch (e) { + print('Exception occurred: $e'); + setState(() { + getPolicyListData = []; + originalPolicyData = []; + filteredPolicyData = []; + }); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getVehicleListSearchData(String val) async { + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchVehicleSearch(val); + + if (response['status'] == 'success') { + print('E113 => getStaffListData => ${response['data']}'); + setState(() { + getVehicleListData = List>.from( + response['data'], + ); + originalVehicleData = getVehicleListData; + filteredVehicleData = List.from(originalVehicleData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getVehicleListData = []; + originalVehicleData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getStaffList( + dynamic managerId, + role, + roleId, { + String fromDate = '', + String toDate = '', + }) async { + print('D68 => Fns called => $managerId | $role'); + setState(() { + isLoading = true; + }); + + final id = int.parse(managerId); + // FORCE BOTH VALUES TO STRING + final String managerIdStr = managerId?.toString() ?? ''; + final String roleStr = role?.toString() ?? ''; + + try { + final response = await apiService.fetchPolicyDataOnlyList( + managerIdStr, + roleStr, + roleStr, + fromDate: controllers['startDate']?.text ?? '', + toDate: controllers['endDate']?.text ?? '', + selectedStaffId: widget.userId ?? '', + ); + + if (response['status'] == 'success') { + final data = response['data']; + print('D81 => getStaffListData => ${response['data']}'); + + final fromDate = response['from_date'] ?? ''; + final toDate = response['to_date'] ?? ''; + + print('FromDate : $fromDate'); + print('ToDate : $toDate'); + setState(() { + controllers['startDate']?.text = fromDate; + controllers['endDate']?.text = toDate; + if (data is List) { + // Already a list of maps + getPolicyData = List>.from(data); + } else if (data is Map) { + // Single object, wrap in a list + getPolicyData = [Map.from(data)]; + } else { + getPolicyData = []; + } + // getStaffData = List>.from(response['data']); + originalData = getPolicyData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getPolicyData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getPolicyFilePath() async { + _pdfViewerKey.currentState?.openBookmarkView(); + + final id = widget.item?['id']; + if (id == null) { + debugPrint('endorsomentValidation: policy id is null, skipping API call'); + return; + } + + if (!mounted) return; + setState(() => isLoading = true); + try { + final url = Uri.parse( + '${Env.apiUrl}endorsement/EndorsementFilePath?endorsement_id=$id', + ); + + setState(() { + pdfUrl = "$url"; + _cachedPdfUrl = pdfUrl; + }); + print("FINAL PDF URL -> $pdfUrl"); + } catch (e, st) { + print('Exception in getPolicyFilePath: $e\n$st'); + } finally { + if (!mounted) return; + setState(() => isLoading = false); + } + } + + // ================= CREATE API ================= + + Future createUserData(data) async { + if (!mounted) return; + + setState(() { + isSubmitLoading = true; // 🔥 START LOADER + }); + + final Uri uri = Uri.parse('${Env.apiUrl}endorsement/updateEndorsement'); + + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + // Use MultipartRequest (POST only) + final request = http.MultipartRequest('POST', uri); + request.headers['Authorization'] = 'Bearer $_token'; + request.headers['app-signature'] = Env.App_Signature; + + print("USerDAta - $data"); + + // userData.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + + data.forEach((key, value) { + // if (key != 'certificate_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + // } + }); + // Attach file if selected + if (docUploadedEndorsFile != null) { + try { + if (docUploadedEndorsFile!.bytes != null) { + final multipartFile = http.MultipartFile.fromBytes( + 'endorsement_file_name', + docUploadedEndorsFile!.bytes!, + filename: docUploadedEndorsFile!.name, + ); + request.files.add(multipartFile); + } + // else if (docUploadedEndorsFile!.path != null) { + // final multipartFile = await http.MultipartFile.fromPath( + // 'endorsement_file_name', + // docUploadedEndorsFile!.path!, + // filename: docUploadedEndorsFile!.name, + // ); + // request.files.add(multipartFile); + // } + print("📎 File attached: ${docUploadedEndorsFile!.name}"); + } catch (e) { + print("❌ Failed to attach file: $e"); + } + } + + print(" Sending request with fields: ${request.fields}"); + + try { + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + print("Response status: ${response.statusCode}"); + print("Response body: ${response.body}"); + + if (response.statusCode == 200 || response.statusCode == 201) { + print("✅ Partner submitted successfully!"); + + print("Response: ${response.body}"); + ToastHelper.showSuccessToast(context, 'Saved Successfully'); + context.pop(true); + + widget.onSubmit("success"); + } else if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + } else { + final responseBody = jsonDecode(response.body); + dynamic msg = responseBody['data']; + + print("Failed to submit plan. Status: ${response.statusCode}"); + print("Error: ${response.body}"); + + ToastHelper.showErrorToast(context, 'Failed To Save'); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } finally { + if (mounted) { + setState(() { + isSubmitLoading = false; // 🔥 STOP LOADER + }); + } + } + } + + // ================= UI ================= + + @override + Widget build(BuildContext context) { + // Ensure global AppHeader remains visible by pushing content down by 64px + return SafeArea( + child: Scaffold( + backgroundColor: Color(0xffD9EBE8), + // ⭐ FIXED BUTTON FOOTER + bottomNavigationBar: Container( + padding: const EdgeInsets.all(16), + color: const Color(0xFFF7FBFA), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, // 👉 move button to right + children: [], + ), + ), + body: Container( + // margin: const EdgeInsets.only(top: 64), // <-- keeps popup under global AppHeader + width: double.infinity, + // height: MediaQuery.of(context).size.height - 64, + color: const Color(0xFFF7FBFA), + child: Column( + children: [ + // In-body header + Container( + height: 56, + color: Color(0xFFE3F9F8), + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: [ + IconButton( + icon: const Icon(Icons.file_open), + onPressed: () => context.pop(), + ), + const Expanded( + child: Text( + 'Endorsement Review', + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.w500, + ), + ), + ), + // if (isLoading) + // const SizedBox( + // width: 12, + // height: 12, + // child: CircularProgressIndicator(strokeWidth: 2), + // ), + const SizedBox(width: 8), + IconButton( + icon: const Icon(Icons.close), + onPressed: () => context.pop(), + ), + ], + ), + ), + + // Body: left PDF preview + right grouped form + Expanded( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + // LEFT - PDF placeholder + Expanded( + flex: 1, + child: Container( + margin: const EdgeInsets.only(right: 12), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'Original Endorsement Document', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + Expanded( + child: PolicyPdfViewer( + pdfUrl: pdfUrl, + ), // 👈 Use separate widget + ), + ], + ), + ), + ), + // RIGHT - Grouped Form + Expanded( + flex: 1, + child: Card( + elevation: 2, + color: Colors.white, + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + /// HEADER + Container( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 18, + ), + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, // 135deg effect + end: Alignment.bottomRight, + colors: [ + Color(0xFFF0FBFB), // #f0fbfb + Color(0xFFFFFFFF), // #ffffff + ], + stops: [0.0, 0.6], // 0% → 60% + ), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + border: const Border( + bottom: BorderSide( + color: Color(0xFFe5e7eb), + width: 1, + ), + ), + ), + child: Row( + children: [ + // Container( + // padding: const EdgeInsets.all(10), + // decoration: BoxDecoration( + // color: const Color(0xFF00b5b5), + // borderRadius: BorderRadius.circular(10), + // ), + // child: Text('📝'), + // // const Icon(Icons.edit, color: Color(0xFF0F766E)), + // ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: const [ + Text( + "Edit Endorsement", + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + // Text( + // "Create a new endorsement request for an active policy", + // style: TextStyle(fontSize: 11, color: Color(0xFF6b7280),fontWeight: FontWeight.w500), + // ), + ], + ), + const Spacer(), + Container( + width: 34, + height: 34, + // padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Color(0xFFe5e7eb), + style: BorderStyle.solid, + ), + ), + child: InkWell( + onTap: () => Navigator.pop(context), + child: const Icon(Icons.close), + ), + ), + ], + ), + ), + + Expanded( + child: Form( + key: _formKeyEndrosment, + autovalidateMode: + AutovalidateMode.disabled, + child: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + Visibility( + visible: !isExternal, + maintainState: true, + maintainAnimation: true, + maintainSize: false, + child: Column( + children: [ + buildSectionTitle( + "SEARCH POLICY", + ), + const SizedBox(height: 15), + + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + /// 🔹 VEHICLE SEARCH + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + buildSearchBox( + controller: + _vehicleSearchController, + hint: + "Search By Vehicle Number", + onChanged: (val) async { + if (val + .isNotEmpty) { + await getVehicleListSearchData( + val, + ); + } else { + setState( + () => + filteredVehicleData + .clear(), + ); + } + }, + ), + + /// 🔹 Vehicle Results Dropdown + if (filteredVehicleData + .isNotEmpty) + Container( + margin: + const EdgeInsets.only( + top: 6, + ), + height: 150, + decoration: BoxDecoration( + color: + Colors.white, + border: Border.all( + color: + const Color( + 0xFFE5E7EB, + ), + ), + borderRadius: + BorderRadius.circular( + 12, + ), + boxShadow: [ + BoxShadow( + color: Colors + .black + .withOpacity( + 0.05, + ), + blurRadius: 6, + ), + ], + ), + child: ListView.builder( + padding: + EdgeInsets + .zero, + itemCount: + filteredVehicleData + .length, + itemBuilder: (context, index) { + final vehicle = + filteredVehicleData[index]; + return InkWell( + onTap: () { + setState(() { + controllers['policyNum'] + ?.text = + vehicle['policy_number'] ?? + ''; + _vehicleSearchController + .text = + vehicle['policy_number'] ?? + ''; + filteredVehicleData + .clear(); + }); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: + 8, + horizontal: + 12, + ), + child: Text( + vehicle['policy_number'] ?? + '-', + style: + _textStyle1, + overflow: + TextOverflow + .ellipsis, + ), + ), + ); + }, + ), + ), + ], + ), + ), + + const SizedBox(width: 20), + + /// 🔹 POLICY SEARCH + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + buildSearchBox( + controller: + _policySearchController, + hint: + "Search By Policy Number", + onChanged: (val) async { + if (val + .isNotEmpty) { + await getPolicyListSearchData( + val, + ); + } else { + setState( + () => + filteredPolicyData + .clear(), + ); + } + }, + ), + + /// 🔹 Policy Results Dropdown + if (filteredPolicyData + .isNotEmpty) + Container( + margin: + const EdgeInsets.only( + top: 6, + ), + height: 150, + decoration: BoxDecoration( + color: + Colors.white, + border: Border.all( + color: + const Color( + 0xFFE5E7EB, + ), + ), + borderRadius: + BorderRadius.circular( + 12, + ), + boxShadow: [ + BoxShadow( + color: Colors + .black + .withOpacity( + 0.05, + ), + blurRadius: 6, + ), + ], + ), + child: ListView.builder( + padding: + EdgeInsets + .zero, + itemCount: + filteredPolicyData + .length, + itemBuilder: (context, index) { + final policy = + filteredPolicyData[index]; + return InkWell( + onTap: () { + setState(() { + controllers['policyNum'] + ?.text = + policy['policy_number'] ?? + ''; + _policySearchController + .text = + policy['policy_number'] ?? + ''; + filteredPolicyData + .clear(); + }); + }, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: + 8, + horizontal: + 12, + ), + child: Text( + policy['policy_number'] ?? + '-', + style: + _textStyle1, + overflow: + TextOverflow + .ellipsis, + ), + ), + ); + }, + ), + ), + ], + ), + ), + ], + ), + + const Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + ], + ), + ), + + /// ENDORSEMENT DETAILS + buildSectionTitle( + "ENDORSEMENT DETAILS", + ), + const SizedBox(height: 20), + + Row( + children: [ + Expanded( + child: buildEndrosPolicyFrom( + context, + ), + ), + const SizedBox(width: 20), + Expanded( + child: buildEndrosType(context), + ), + ], + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: buildPolicyNumber(context), + ), + const SizedBox(width: 20), + Expanded( + child: buildEndorsementNoField( + context, + ), + ), + ], + ), + + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: buildContactPersonField( + context, + ), + ), + const SizedBox(width: 20), + Spacer(), + // Expanded(child: buildPendingDaysField(context)), + ], + ), + + Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + + if (isExternal) ...[ + buildSectionTitle( + "POLICY INFORMATION", + ), + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: buildRegNoField(context), + ), + const SizedBox(width: 20), + Expanded( + child: buildBrokerDropdown( + context, + ), + ), + // Expanded(child: buildPendingDaysField(context)), + ], + ), + const SizedBox(height: 25), + Row( + children: [ + Expanded( + child: buildPolicyStartDate( + context, + ), + ), + SizedBox(width: 20), + Expanded( + child: buildPolicyEndDate( + context, + ), + ), + ], + ), + const SizedBox(height: 25), + Row( + children: [ + Expanded( + child: buildInsurerDropdown( + context, + ), + ), + const SizedBox(width: 20), + Expanded( + child: buildInsuredNameField( + context, + ), + ), + ], + ), + + Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + ], + + /// UPLOAD & REMARKS + buildSectionTitle("UPLOAD & REMARKS"), + const SizedBox(height: 20), + + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Expanded(child: buildUploadBox()), + const SizedBox(width: 25), + Expanded( + child: buildEndrosRemarks( + context, + ), + ), + ], + ), + + Divider( + color: Color(0xFFe5e7eb), + thickness: 1, + height: 40, + ), + + /// Financial & Status + buildSectionTitle("Financial & Status"), + const SizedBox(height: 20), + + /// FINANCIAL + Row( + children: [ + Expanded( + child: buildFinancialToggle(), + ), + const SizedBox(width: 20), + Expanded( + child: showFinancialFields + ? buildPaymentModeDropdown() + : const Spacer(), // 👈 match dropdown total height + ), + ], + ), + + if (showFinancialFields) ...[ + const SizedBox(height: 20), + Row( + children: [ + Expanded( + child: buildPremiumField( + context, + ), + ), + const SizedBox(width: 20), + Expanded( + child: buildCommissionField( + context, + ), + ), + ], + ), + ], + + const SizedBox(height: 20), + + Row( + children: [ + Expanded( + child: buildLifecycleStatus(), + ), + const SizedBox(width: 25), + Spacer(), + // Expanded(child: buildVerificationStatus()), + ], + ), + + /// SAVE BUTTON + // Align( + // alignment: Alignment.centerRight, + // child: ElevatedButton( + // style: ElevatedButton.styleFrom( + // backgroundColor: const Color(0xFF0F766E), + // padding: const EdgeInsets.symmetric( + // horizontal: 40, + // vertical: 14, + // ), + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(25), + // ), + // ), + // onPressed: () { + // if (!_formKeyEndrosment.currentState!.validate()) return; + // final dataSet = endrosmentDetails(); + // createUserData(dataSet); + // }, + // child: const Text( + // "Save Endorsement", + // style: TextStyle(fontSize: 13), + // ), + // ), + // ), + ], + ), + ), + ), + ), + + SizedBox(height: 20), + + Container( + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 18, + ), + decoration: const BoxDecoration( + border: Border( + top: BorderSide(color: Color(0xFFE5E7EB)), + ), + ), + child: Row( + children: [ + /// Left Side - Required text + const Text( + "* Required fields", + style: TextStyle( + fontSize: 11, + color: Color(0xFF6B7280), + ), + ), + + const Spacer(), + + /// Cancel Button + Container( + height: 44, + margin: const EdgeInsets.only(right: 14), + child: OutlinedButton( + onPressed: () => Navigator.pop(context), + style: OutlinedButton.styleFrom( + backgroundColor: Colors.white, + side: const BorderSide( + color: Color(0xFFE5E7EB), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 12, + ), + ), + padding: const EdgeInsets.symmetric( + horizontal: 24, + ), + ), + child: const Text( + "Cancel", + style: TextStyle( + fontSize: 13, + color: Color(0xFF374151), + fontWeight: FontWeight.w400, + ), + ), + ), + ), + + /// Save Button + ValueListenableBuilder( + valueListenable: commissionController, + builder: (context, value, _) { + final bool isVerifiedAllowed = + widget + .item?['is_data_accuracy_checked'] + ?.toString() == + '0'; + + final bool hasCommission = value.text + .trim() + .isNotEmpty; + + final bool isEnabled = + isVerifiedAllowed && hasCommission; + + return Container( + height: 44, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular( + 12, + ), + + /// 🔥 Dynamic Gradient + gradient: isEnabled + ? const LinearGradient( + colors: [ + Color(0xFF14B8A6), + Color(0xFF0F766E), + ], + ) + : const LinearGradient( + colors: [ + Color(0xFFE5E7EB), + Color(0xFFD1D5DB), + ], + ), + + boxShadow: isEnabled + ? [ + BoxShadow( + color: const Color( + 0xFF0F766E, + ).withOpacity(0.25), + blurRadius: 8, + offset: const Offset( + 0, + 4, + ), + ), + ] + : [], + ), + + child: ElevatedButton( + onPressed: (!isVerifiedAllowed || isSubmitLoading) + ? null + : () { + if (!_formKeyEndrosment.currentState!.validate()) return; + + if (showFinancialFields && !hasCommission) { + ToastHelper.showErrorToast( + context, + "Please enter Commission Amount", + ); + return; + } + + final dataSet = endrosmentDetails(); + createUserData(dataSet); + }, + + style: ElevatedButton.styleFrom( + backgroundColor: + Colors.transparent, + shadowColor: Colors.transparent, + padding: + const EdgeInsets.symmetric( + horizontal: 26, + ), + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(12), + ), + ), + + child: isSubmitLoading + ? const SizedBox( + height: 18, + width: 18, + child: + CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : Row( + mainAxisSize: + MainAxisSize.min, + children: [ + const Icon( + Icons.save, + size: 18, + ), + const SizedBox(width: 8), + Text( + roleId == 'Accounts' + ? 'Confirm Data Accuracy' + : 'Update Endorsement', + style: TextStyle( + fontSize: 13, + fontWeight: + FontWeight.w500, + color: isEnabled + ? Colors.white + : const Color( + 0xFF6B7280, + ), + ), + ), + ], + ), + ), + ); + }, + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } + + Widget stepCircle(int number, bool completed, bool active) { + if (completed) { + return Container( + width: 28, + height: 28, + decoration: const BoxDecoration( + color: Color(0xFF16A34A), + shape: BoxShape.circle, + ), + child: const Icon(Icons.check, size: 16, color: Colors.white), + ); + } + + if (active) { + return Container( + width: 32, + height: 32, + decoration: const BoxDecoration( + color: Color(0xFFd4edef), // outer grey ring + shape: BoxShape.circle, + ), + child: Center( + child: Container( + width: 26, + height: 26, + decoration: const BoxDecoration( + color: Color(0xFF00b5b5), // teal inner + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + number.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ); + } + + return Container( + width: 28, + height: 28, + decoration: const BoxDecoration( + color: Color(0xFFE5E7EB), + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + number.toString(), + style: const TextStyle( + color: Color(0xFF6B7280), + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ); + } + + Widget buildSearchBox({ + required TextEditingController controller, + required String hint, + required Function(String) onChanged, + }) { + final FocusNode focusNode = FocusNode(); + bool isFocused = false; + + return StatefulBuilder( + builder: (context, setStateSB) { + focusNode.addListener(() { + setStateSB(() { + isFocused = focusNode.hasFocus; + }); + }); + + return Container( + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: isFocused + ? const Color(0xFF008f8f) // teal border + : const Color(0xFFE5E7EB), + width: 1.5, + ), + boxShadow: isFocused + ? [ + BoxShadow( + color: const Color(0xFF008f8f).withOpacity(0.15), + blurRadius: 8, + spreadRadius: 1, + ), + ] + : [], + ), + child: Row( + children: [ + Expanded( + child: TextField( + focusNode: focusNode, + controller: controller, + onChanged: onChanged, + style: const TextStyle( + fontSize: 13, + color: Color(0xFF374151), + ), + decoration: InputDecoration( + hintText: hint, + hintStyle: const TextStyle( + color: Color(0xFF9CA3AF), + fontSize: 13, + ), + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + horizontal: 14, + vertical: 15, + ), + ), + ), + ), + + /// Search Icon Button + Container( + margin: const EdgeInsets.only(right: 8), + width: 30, + height: 30, + decoration: BoxDecoration( + color: const Color(0xFF008f8f), + borderRadius: BorderRadius.circular(10), + ), + child: const Icon(Icons.search, color: Colors.white, size: 18), + ), + ], + ), + ); + }, + ); + } + + Widget buildUploadBox() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + /// Label Row + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + Text( + "Upload Document", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + Text( + "PDF / JPG / PNG", + style: TextStyle(fontSize: 10, color: Color(0xFF6B7280)), + ), + ], + ), + const SizedBox(height: 10), + + /// 🔹 IF EXISTING FILE (EDIT MODE) + if (showExistingFile && existingFileName != null) + Container( + height: 70, + padding: const EdgeInsets.symmetric(horizontal: 14), + decoration: BoxDecoration( + color: const Color(0xFFF8FAFC), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFF0F766E), width: 1.5), + ), + child: Row( + children: [ + const Icon(Icons.insert_drive_file, color: Color(0xFF0F766E)), + + const SizedBox(width: 12), + + Expanded( + child: Text( + existingFileName!, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w400, + ), + ), + ), + + /// ❌ REMOVE BUTTON + GestureDetector( + onTap: () { + setState(() { + showExistingFile = false; + existingFileName = null; + docUploadedEndorsFile = null; + }); + }, + child: const Icon(Icons.close, color: Colors.red), + ), + ], + ), + ) + /// 🔹 ELSE SHOW UPLOAD BOX + else + GestureDetector( + onTap: () async { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['pdf', 'jpg', 'jpeg', 'png'], + ); + + if (result != null) { + setState(() { + docUploadedEndorsFile = result.files.first; + }); + } + }, + child: Container( + height: 160, + decoration: BoxDecoration( + color: const Color(0xFFF8FAFC), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFF0F766E), width: 1.5), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.attach_file, + size: 34, + color: Color(0xFF9CA3AF), + ), + const SizedBox(height: 12), + Text( + docUploadedEndorsFile != null + ? docUploadedEndorsFile!.name + : "Click to upload or drag & drop", + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w400, + color: Color(0xFF374151), + ), + ), + const SizedBox(height: 6), + const Text( + "Endorsement document, policy copy", + style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)), + ), + const SizedBox(height: 10), + + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + buildFileChip("PDF"), + const SizedBox(width: 8), + buildFileChip("JPG"), + const SizedBox(width: 8), + buildFileChip("PNG"), + const SizedBox(width: 8), + buildFileChip("Max 5MB"), + ], + ), + ], + ), + ), + ), + ], + ); + } + + // Widget buildUploadBox() { + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // /// Label Row + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: const [ + // Text( + // "Upload Document", + // style: TextStyle( + // fontSize: 12, + // fontWeight: FontWeight.w500, + // color: Color(0xFF374151), + // ), + // ), + // Text( + // "PDF / JPG / PNG", + // style: TextStyle( + // fontSize: 10, + // color: Color(0xFF6B7280), + // ), + // ), + // ], + // ), + // const SizedBox(height: 10), + // + // /// Upload Container + // GestureDetector( + // onTap: () async { + // FilePickerResult? result = + // await FilePicker.platform.pickFiles(); + // + // if (result != null) { + // setState(() { + // docUploadedEndorsFile = + // result.files.first; + // }); + // } + // }, + // child: Container( + // height: 160, + // decoration: BoxDecoration( + // color: const Color(0xFFF8FAFC), + // borderRadius: BorderRadius.circular(14), + // border: Border.all( + // color: const Color(0xFF0F766E), + // width: 1.5, + // style: BorderStyle.solid, + // ), + // ), + // child: Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // const Icon( + // Icons.attach_file, + // size: 34, + // color: Color(0xFF9CA3AF), + // ), + // const SizedBox(height: 12), + // Text( + // docUploadedEndorsFile != null + // ? docUploadedEndorsFile!.name + // : "Click to upload or drag & drop", + // style: const TextStyle( + // fontSize: 13, + // fontWeight: FontWeight.w400, + // color: Color(0xFF374151), + // ), + // ), + // const SizedBox(height: 6), + // const Text( + // "Endorsement document, policy copy", + // style: TextStyle( + // fontSize: 11, + // color: Color(0xFF6B7280), + // ), + // ), + // const SizedBox(height: 10), + // + // /// File Type Chips + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // buildFileChip("PDF"), + // const SizedBox(width: 8), + // buildFileChip("JPG"), + // const SizedBox(width: 8), + // buildFileChip("PNG"), + // const SizedBox(width: 8), + // buildFileChip("Max 5MB"), + // ], + // ) + // ], + // ), + // ), + // ), + // ], + // ); + // } + + Widget buildFileChip(String text) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: const Color(0xFFE5E7EB), + borderRadius: BorderRadius.circular(8), + ), + child: Text( + text, + style: const TextStyle(fontSize: 10, color: Color(0xFF374151)), + ), + ); + } + + Widget buildSectionTitle(String title) { + return Row( + children: [ + Container(width: 3, height: 14, color: Color(0xFF00b5b5)), + const SizedBox(width: 8), + Text( + title, + style: TextStyle( + fontWeight: FontWeight.w700, + fontSize: 10, + letterSpacing: 2, + color: Color(0xFF6b7280), + ), + ), + ], + ); + } + + Widget buildPolicyNumber(context) { + return buildCommonTextField( + label: "Policy Number", + controller: controllers['policyNum']!, + isRequired: true, + readOnly: isInternal, + isFocused: isPolicyNumberFocused, + onFocusChanged: (val) { + setState(() { + isPolicyNumberFocused = val; + }); + }, + ); + } + + //------------------------- Endrosment Part ----------------------------------- + + Widget buildEndrosRemarks(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Remarks", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const SizedBox(height: 10), + + Container( + height: 160, // 👈 textarea height + decoration: BoxDecoration( + color: const Color(0xFFF9FAFB), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFFE5E7EB)), + ), + child: TextFormField( + controller: controllers['remarks'], + keyboardType: TextInputType.multiline, + maxLines: null, // allow unlimited lines + textAlignVertical: TextAlignVertical.top, + style: const TextStyle(fontSize: 13, color: Color(0xFF374151)), + decoration: const InputDecoration( + hintText: + "Describe the reason for this endorsement request, changes being made, or any additional instructions...", + hintStyle: TextStyle(fontSize: 12, color: Color(0xFF9CA3AF)), + border: InputBorder.none, + contentPadding: EdgeInsets.all(16), + ), + // validator: (value) => + // Validators.requiredField(value, "remarks"), + ), + ), + ], + ); + } + + Widget buildPolicyStartDate(context) { + return buildDateField( + context, + "Policy Start Date", + policyStartController, + isStartDateFocused, + (val) => setState(() => isStartDateFocused = val), + ); + } + + Widget buildPolicyEndDate(context) { + return buildDateField( + context, + "Policy End Date", + policyEndController, + isEndDateFocused, + (val) => setState(() => isEndDateFocused = val), + ); + } + + Widget buildDateField( + BuildContext context, + String label, + TextEditingController controller, + bool isFocused, + Function(bool) onFocusChanged, + ) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: '$label *', + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + children: label.contains("*") + ? const [ + TextSpan( + text: " *", + style: TextStyle(color: Colors.red), + ), + ] + : [], + ), + ), + const SizedBox(height: 8), + + AnimatedContainer( + duration: const Duration(milliseconds: 180), + constraints: const BoxConstraints(minHeight: 40), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(14)), + child: GestureDetector( + onTap: () async { + onFocusChanged(true); + + DateTime? picked = await showDatePicker( + context: context, + firstDate: DateTime(2000), + lastDate: DateTime.now(), + initialDate: DateTime.now(), + ); + + onFocusChanged(false); + + if (picked != null) { + controller.text = + "${picked.day.toString().padLeft(2, '0')}-" + "${picked.month.toString().padLeft(2, '0')}-" + "${picked.year}"; + } + }, + child: AbsorbPointer( + child: TextFormField( + controller: controller, + validator: (value) { + if (isExternal && (value == null || value.isEmpty)) { + return "$label is required"; + } + return null; + }, + readOnly: true, + style: const TextStyle(fontSize: 13, color: Color(0xFF374151)), + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + + isDense: true, // ⭐ important + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + helperText: " ", + helperStyle: const TextStyle(height: 0.8), + + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + + suffixIcon: const Icon( + Icons.calendar_today_outlined, + size: 18, + color: Color(0xFF6B7280), + ), + ), + ), + ), + ), + ), + ], + ); + } + + Widget buildRegNoField(context) { + return buildCommonTextField( + label: "Vehicle Number", + controller: regNoController, + isRequired: isExternal, + isFocused: isRegNoFocused, + onFocusChanged: (val) { + setState(() => isRegNoFocused = val); + }, + ); + } + + Widget buildInsuredNameField(context) { + return buildCommonTextField( + label: "Insured Name", + controller: insuredNameController, + isRequired: isExternal, + isFocused: isInsuredNameFocused, + onFocusChanged: (val) { + setState(() => isInsuredNameFocused = val); + }, + ); + } + + Widget buildEndorsementNoField(context) { + return buildCommonTextField( + label: "Endorsement No", + controller: endorsementNoController, + isRequired: false, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9]')), + ], + isFocused: isEndorsementNoFocused, + onFocusChanged: (val) { + setState(() => isEndorsementNoFocused = val); + }, + ); + } + + Widget buildContactPersonField(context) { + return buildCommonTextField( + label: "Contact Person", + controller: contactPersonController, + isRequired: false, + isFocused: isContactPersonFocused, + onFocusChanged: (val) { + setState(() => isContactPersonFocused = val); + }, + ); + } + + // Widget buildPendingDaysField(context) { + // return buildCommonTextField( + // label: "Pending Days", + // controller: pendingDaysController, + // isRequired: isInternal, + // keyboardType: TextInputType.number, + // isFocused: isPendingDaysFocused, + // onFocusChanged: (val) { + // setState(() => isPendingDaysFocused = val); + // }, + // ); + // } + + Widget buildPremiumField(context) { + return buildCommonTextField( + label: "Endorsement Premium", + controller: premiumController, + isRequired: showFinancialFields, + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + isFocused: isPremiumFocused, + onFocusChanged: (val) { + setState(() => isPremiumFocused = val); + }, + ); + } + + Widget buildCommissionField(context) { + return buildCommonTextField( + label: "Commission Amount", + controller: commissionController, + isRequired: showFinancialFields, + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + isFocused: isCommissionFocused, + onFocusChanged: (val) { + setState(() => isCommissionFocused = val); + }, + ); + } + + Widget buildCommonTextField({ + required String label, + required TextEditingController controller, + required bool isRequired, + bool readOnly = false, + TextInputType keyboardType = TextInputType.text, + List? inputFormatters, + required bool isFocused, + required Function(bool) onFocusChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: label, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + children: isRequired + ? const [ + TextSpan( + text: " *", + style: TextStyle(color: Colors.red), + ), + ] + : [], + ), + ), + const SizedBox(height: 8), + TextFormField( + controller: controller, + readOnly: readOnly, + keyboardType: keyboardType, + inputFormatters: inputFormatters, + validator: (value) { + if (isRequired && (value == null || value.trim().isEmpty)) { + return "$label is required"; + } + return null; + }, + style: const TextStyle(fontSize: 13, color: Color(0xFF374151)), + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + + isDense: true, // ⭐ important + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + + helperText: " ", // 🔥 IMPORTANT FIX + helperStyle: const TextStyle(height: 0.8), + + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + ), + ), + // AnimatedContainer( + // duration: const Duration(milliseconds: 180), + // constraints: const BoxConstraints( + // minHeight: 40, + // ), + // decoration: BoxDecoration( + // color: isFocused ? Colors.white : const Color(0xFFF9FAFB), + // borderRadius: BorderRadius.circular(14), + // border: Border.all( + // color: isFocused + // ? const Color(0xFF0F766E) + // : const Color(0xFFE5E7EB), + // width: 1.5, + // ), + // boxShadow: isFocused + // ? [ + // BoxShadow( + // color: Color(0xFF0F766E).withOpacity(0.12), + // blurRadius: 6, + // spreadRadius: 1, + // ) + // ] + // : [], + // ), + // child: Focus( + // onFocusChange: onFocusChanged, + // child: TextFormField( + // controller: controller, + // readOnly: readOnly, + // validator: (value) { + // if (isRequired) { + // if (value == null || value.trim().isEmpty) { + // return "$label is required"; + // } + // } + // return null; + // }, + // keyboardType: keyboardType, + // style: const TextStyle( + // fontSize: 13, + // color: Color(0xFF374151), + // ), + // decoration: const InputDecoration( + // border: InputBorder.none, + // isDense: true, + // contentPadding: const EdgeInsets.symmetric( + // horizontal: 16, + // vertical: 10, + // ), + // ), + // ), + // ), + // ), + ], + ); + } + + Widget buildFinancialToggle() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Financial Status", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const Text(" *", style: TextStyle(color: Colors.red)), + const SizedBox(width: 12), + + /// 👇 IMPORTANT PART + Expanded( + child: const Text( + "Additional premium?", + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)), + ), + ), + ], + ), + const SizedBox(height: 8), + + /// Segmented Container + Container( + height: 40, + decoration: BoxDecoration( + color: const Color(0xFFF3F4F6), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFFE5E7EB)), + ), + child: Row( + children: [ + /// YES BUTTON + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + financialType = "Yes"; + showFinancialFields = true; + + // 🔥 Clear old values + premiumController.clear(); + commissionController.clear(); + selectedPaymentModeId = null; + }); + }, + child: Container( + decoration: BoxDecoration( + color: financialType == "Yes" + ? const Color(0xFF16a34a) + : Colors.transparent, + borderRadius: BorderRadius.circular(14), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.check, + size: 16, + color: financialType == "Yes" + ? const Color(0xFFFFFFFF) + : const Color(0xFF9CA3AF), + ), + const SizedBox(width: 6), + Text( + "Yes", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + color: financialType == "Yes" + ? const Color(0xFFFFFFFF) + : const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ), + ), + + /// Divider + Container(width: 1, color: const Color(0xFFE5E7EB)), + + /// NO BUTTON + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + financialType = "No"; + showFinancialFields = false; + + // 🔥 Clear old values + premiumController.clear(); + commissionController.clear(); + selectedPaymentModeId = null; + }); + }, + child: Container( + decoration: BoxDecoration( + color: financialType == "No" + ? const Color(0xFFE5E7EB) + : Colors.transparent, + borderRadius: BorderRadius.circular(14), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.close, + size: 16, + color: financialType == "No" + ? const Color(0xFF374151) + : const Color(0xFF9CA3AF), + ), + const SizedBox(width: 6), + Text( + "No", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + color: financialType == "No" + ? const Color(0xFF374151) + : const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + + /// ⭐ IMPORTANT: reserve space like TextFormField + const SizedBox(height: 20), + ], + ); + } + + Widget buildSegmentedStatus({ + required String title, + required List> options, + required String selectedValue, + required Function(String) onChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + title, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + ), + const Text(" *", style: TextStyle(color: Colors.red)), + ], + ), + const SizedBox(height: 12), + + Row( + children: options.map((option) { + final bool isSelected = selectedValue == option["value"]; + + return Expanded( + child: GestureDetector( + onTap: () => onChanged(option["value"]), + child: Container( + height: 40, + margin: const EdgeInsets.only(right: 12), + decoration: BoxDecoration( + color: isSelected + ? option["selectedColor"] + : const Color(0xFFF3F4F6), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: isSelected + ? option["borderColor"] ?? option["selectedColor"] + : const Color(0xFFE5E7EB), + ), + ), + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + option["icon"], + size: 16, + color: isSelected + ? option["textColor"] ?? const Color(0xFF111827) + : const Color(0xFF6B7280), + ), + const SizedBox(width: 6), + Text( + option["label"], + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w400, + color: isSelected + ? option["textColor"] ?? const Color(0xFF111827) + : const Color(0xFF6B7280), + ), + ), + ], + ), + ), + ), + ); + }).toList(), + ), + ], + ); + } + + Widget buildLifecycleStatus() { + return buildSegmentedStatus( + title: "Lifecycle Status", + selectedValue: lifecycleStatus, + options: [ + { + "label": "Open", + "value": "Open", + "icon": Icons.circle, + "selectedColor": const Color(0xFFfef3c7), // 🔥 Yellow + "textColor": const Color(0xFF92400E), + }, + { + "label": "Closed", + "value": "Closed", + "icon": Icons.circle, + "selectedColor": const Color(0xFFdcfce7A), // Green light + "textColor": const Color(0xFF065F46), + }, + ], + onChanged: (val) { + setState(() { + lifecycleStatus = val; + print(lifecycleStatus); + }); + }, + ); + } + + Widget buildVerificationStatus() { + return buildSegmentedStatus( + title: "Verification Status", + selectedValue: verificationStatus, + options: [ + { + "label": "To Verify", + "value": "To Verify", + "icon": Icons.diamond, + "selectedColor": const Color(0xFF93C5FD), // 🔥 Blue + "textColor": const Color(0xFF1E40AF), + }, + { + "label": "Verified", + "value": "Verified", + "icon": Icons.check_box, + "selectedColor": const Color(0xFFD1FAE5), + "textColor": const Color(0xFF065F46), + }, + ], + onChanged: (val) { + setState(() { + verificationStatus = val; + }); + }, + ); + } + + Widget buildCommonDropdown({ + required String label, + required String hintText, + required List> items, + required Map? selectedItem, + required String Function(Map) itemAsString, + required Function(Map?) onChanged, + required bool isRequired, + required bool isFocused, + required Function(bool) onFocusChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RichText( + text: TextSpan( + text: label, + style: const TextStyle( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF374151), + ), + children: isRequired + ? const [ + TextSpan( + text: " *", + style: TextStyle(color: Colors.red), + ), + ] + : [], + ), + ), + const SizedBox(height: 8), + + Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(14)), + child: DropdownSearch>( + selectedItem: selectedItem, + items: (f, i) => items, + itemAsString: itemAsString, + compareFn: (item, s) => item['id'].toString() == s['id'].toString(), + onChanged: onChanged, + + validator: (value) { + if (isRequired && value == null) { + return "$label is required"; + } + return null; + }, + + onBeforePopupOpening: (val) async { + onFocusChanged(true); + return true; + }, + + popupProps: PopupProps.menu( + onDismissed: () { + onFocusChanged(false); + }, + showSearchBox: true, + ), + + decoratorProps: DropDownDecoratorProps( + decoration: InputDecoration( + filled: true, + fillColor: const Color(0xFFF9FAFB), + + isDense: true, // ⭐ important + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 13, + ), + + helperText: " ", // 🔥 IMPORTANT FIX + helperStyle: const TextStyle(height: 0.8), + + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFFE5E7EB), + width: 1.5, + ), + ), + + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide( + color: Color(0xFF0F766E), + width: 1.5, + ), + ), + + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: const BorderSide(color: Colors.red, width: 1.5), + ), + + errorStyle: const TextStyle(fontSize: 11, height: 1.3), + ), + ), + ), + ), + ], + ); + } + + Widget buildEndrosType(context) { + Map? selectedItem = filteredEndrosmentData.firstWhere( + (item) => item['id'].toString() == selectedEndorsement, + orElse: () => {}, + ); + + return buildCommonDropdown( + label: "Endorsement Type", + hintText: "Select Endorsement Type", + isRequired: true, + items: filteredEndrosmentData, + selectedItem: selectedItem.isNotEmpty ? selectedItem : null, + isFocused: isEndorsementTypeFocused, + onFocusChanged: (val) { + setState(() { + isEndorsementTypeFocused = val; + }); + }, + itemAsString: (val) => val['endorsement_type'].toString(), + onChanged: (val) { + if (val != null) { + setState(() { + selectedEndorsement = val['id']; + }); + } + }, + ); + } + + Widget buildEndrosPolicyFrom(context) { + Map? selectedItem = + policyFromOptions + .where( + (item) => item['policy_from'] == selectedEndrosementPolicyFrom, + ) + .isNotEmpty + ? policyFromOptions.firstWhere( + (item) => item['policy_from'] == selectedEndrosementPolicyFrom, + ) + : null; + + return buildCommonDropdown( + label: "Policy From", + hintText: "Select Policy From", + isRequired: true, + items: policyFromOptions, + selectedItem: selectedItem, + itemAsString: (val) => val['policy_from'], + isFocused: isPolicyFromFocused, + onFocusChanged: (val) { + setState(() { + isPolicyFromFocused = val; + }); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedEndrosementPolicyFrom = val['policy_from']; + + isInternal = selectedEndrosementPolicyFrom == "Internal"; + isExternal = selectedEndrosementPolicyFrom == "External"; + + /// 🔥 POLICY NUMBER LOGIC + if (isExternal) { + controllers['policyNum']!.clear(); + _vehicleSearchController.clear(); + _policySearchController.clear(); + filteredVehicleData.clear(); + filteredPolicyData.clear(); + isPolicyNumberReadOnly = false; + controllers['policyNum']!.clear(); + } else { + isPolicyNumberReadOnly = true; + } + + // 🔥 CLEAR FIELDS WHEN SWITCHING + if (isInternal) { + selectedInsurer = null; + selectedBroker = null; + selectedPaymentModeId = null; + + insuredNameController.clear(); + regNoController.clear(); + policyStartController.clear(); + policyEndController.clear(); + } + + if (isExternal) { + endorsementNoController.clear(); + contactPersonController.clear(); + // pendingDaysController.clear(); + } + + showFinancialFields = financialType == "Yes"; + }); + } + }, + ); + } + + Widget buildInsurerDropdown(context) { + Map? selectedItem = + insurerList + .where( + (item) => item['id']?.toString() == selectedInsurer?.toString(), + ) + .isNotEmpty + ? insurerList.firstWhere( + (item) => item['id']?.toString() == selectedInsurer?.toString(), + ) + : null; + + return buildCommonDropdown( + label: "Insurer", + hintText: "Select Insurer", + isRequired: isExternal, + items: insurerList, + selectedItem: selectedItem, + itemAsString: (val) => val['short_name'] ?? val['name'] ?? "", + isFocused: isInsurerFocused, + onFocusChanged: (val) { + setState(() => isInsurerFocused = val); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedInsurer = val['id']; + }); + } + }, + ); + } + + Widget buildBrokerDropdown(context) { + Map? selectedItem = + brokerList + .where( + (item) => item['id']?.toString() == selectedBroker?.toString(), + ) + .isNotEmpty + ? brokerList.firstWhere( + (item) => item['id']?.toString() == selectedBroker?.toString(), + ) + : null; + + return buildCommonDropdown( + label: "Broker", + hintText: "Select Broker", + isRequired: isExternal, + items: brokerList, + selectedItem: selectedItem, + itemAsString: (val) => val['short_name'] ?? val['name'] ?? "", + isFocused: isBrokerFocused, + onFocusChanged: (val) { + setState(() => isBrokerFocused = val); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedBroker = val['id']; + }); + } + }, + ); + } + + Widget buildPaymentModeDropdown() { + Map? selectedItem = + getPaymentModeData + .where( + (item) => + item['id']?.toString() == selectedPaymentModeId?.toString(), + ) + .isNotEmpty + ? getPaymentModeData.firstWhere( + (item) => + item['id']?.toString() == selectedPaymentModeId?.toString(), + ) + : null; + + return buildCommonDropdown( + label: "Payment Mode", + hintText: "Select Payment Mode", + isRequired: true, + items: getPaymentModeData, + selectedItem: selectedItem, + + /// 🔥 IMPORTANT FIX HERE + itemAsString: (val) => val['value'] ?? "", + + isFocused: isPaymentModeFocused, + onFocusChanged: (val) { + setState(() => isPaymentModeFocused = val); + }, + onChanged: (val) { + if (val != null) { + setState(() { + selectedPaymentModeId = val['id'].toString(); + }); + } + }, + ); + } + // ------------------- STyle --------------------------------- + + static final TextStyle _textStyle = TextStyle( + fontSize: 11, + fontWeight: FontWeight.w400, + ); + static final TextStyle _textStyle1 = TextStyle( + fontSize: 9, + fontWeight: FontWeight.w300, + ); +} diff --git a/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart b/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart index 1164828..bbca5eb 100644 --- a/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart +++ b/lib/presentation/screens/Enquiry/policy_claims_endros/endrosment.dart @@ -1,3 +1,4 @@ +import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -11,19 +12,22 @@ import '../../../../data/utils/Pagination.dart'; import '../../../layouts/main_layout.dart'; import '../../../layouts/responsive_layout.dart'; import '../../../providers/manager_provider.dart'; +import '../../../themes/indicators/date_field_theme.dart'; import '../../../themes/indicators/export_btn.dart'; +import '../../../themes/indicators/input_field_decoration.dart'; import '../../../themes/indicators/search_field_theme.dart'; import '../../../widgets/custom_action_popup.dart'; import '../enquiry/policy_popup.dart'; import '../enquiry/updateEndorsementDialog.dart'; +import 'create_endorsement_dialog.dart'; -class endosement extends ConsumerStatefulWidget { - const endosement({super.key}); +class Endorsement extends ConsumerStatefulWidget { + const Endorsement({super.key}); @override - ConsumerState createState() => endosementState(); + ConsumerState createState() => endosementState(); } -class endosementState extends ConsumerState { +class endosementState extends ConsumerState { int currentPage = 1; int itemsPerPage = 10; late ApiService apiService; @@ -37,54 +41,110 @@ class endosementState extends ConsumerState { dynamic roleId; dynamic managerId; + // bool isDrawerOpen = false; + Map? selectedRow; + List> endorsementNumbers = []; + + List> getEndrosmentType = []; + List> filteredEndrosmentData = []; + String? hoveredRowId; + + @override void initState() { super.initState(); apiService = ApiService(); - Future.microtask(() { + Future.microtask(() async { final id = ref.read(managerIdProvider); managerId = ref.read(managerIdProvider); roleId = ref.read(userRoleProvider); userId = ref.read(userIdProvider); print("F46 => r : $roleId | mId: $id | uId: $userId "); - if (userId != null) { - getStaffList(managerId, userId, roleId); + /// ⭐ DEFAULT FILTER FOR ACCOUNTS + if (roleId == 'Accounts') { + selectedVerificationVal = 0; // 0 = To Verify + } else { + selectedStatusVal = 'Open'; } + + if (userId != null) { + await getStaffList(managerId, userId, roleId); + } + getEnroementType(); + getInsurerDetails(); }); } Future getStaffList(int managerId, userId, role) async { - print('F53 => Fns called => $managerId | $role'); setState(() { isLoading = true; }); + print('fetchEndorsementList first $selectedVerificationVal'); + try { final response = await apiService.fetchEndorsementList( managerId, userId, role, + + fromDate: startController.text.isNotEmpty + ? DateFormat('yyyy-MM-dd') + .format(DateFormat('dd-MM-yyyy') + .parse(startController.text)) + : null, + + toDate: endController.text.isNotEmpty + ? DateFormat('yyyy-MM-dd') + .format(DateFormat('dd-MM-yyyy') + .parse(endController.text)) + : null, + + endorsementType: + selectedEndorsementTypeVal?.toString(), + + insurerId: + selectedInsurerVal?.toString(), + + status: selectedStatusVal == 'All' + ? '' + : selectedStatusVal == 'Open' + ? 'Open' + : selectedStatusVal == 'Closed' + ? 'Closed' + : null, + + + verification: selectedVerificationVal == 2 + ? '' + : selectedVerificationVal == 0 + ? 'To Verify' + : selectedVerificationVal == 1 + ? 'Verified' + : null, + // selectedVerificationVal?.toString(), ); + print('fetchEndorsementList'); if (response['status'] == 'success') { final data = response['data']; - print('F62 => End rse mnt List => ${response['data']}'); + setState(() { if (data is List) { - // Already a list of maps - getStaffData = List>.from(data); + getStaffData = + List>.from(data); } else if (data is Map) { - // Single object, wrap in a list - getStaffData = [Map.from(data)]; + getStaffData = [ + Map.from(data) + ]; } else { getStaffData = []; } - // getStaffData = List>.from(response['data']); + originalData = getStaffData; filteredData = List.from(originalData); - // print('originalData - $getClaimPolicies'); }); } else { getStaffData = []; @@ -121,37 +181,46 @@ class endosementState extends ConsumerState { } void filterData(String query) { - print("FilterDAta - $query"); + final lowerQuery = query.toLowerCase(); + setState(() { filteredData = getStaffData.where((item) { - // final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive"; - return (item['reg_no'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ) || - (item['policy_from'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ) || - (item['status'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ) || - (item['insurer_short_name'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ) || - (item['policy_number'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ) || - (item['endorsement_type_value'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ) || - (item['endorsement_no'] ?? '-').toLowerCase().contains( - query.toLowerCase(), - ); + /// 🔹 Search all raw values + final matchesRawValues = item.values.any( + (value) => + value != null && + value.toString().toLowerCase().contains(lowerQuery), + ); + + /// 🔹 Add computed verification text + final verificationText = + item['is_data_accuracy_checked'] == '0' + ? 'to verify' + : 'verified'; + + final matchesVerification = + verificationText.contains(lowerQuery); + + return matchesRawValues || matchesVerification; + }).toList(); }); } - final TextEditingController _searchStaffController = TextEditingController(); + final TextEditingController rightSearchController = TextEditingController(); + final TextEditingController startController = TextEditingController(); + final TextEditingController endController = TextEditingController(); + + dynamic selectedStatusVal; + dynamic selectedVerificationVal; + dynamic selectedInsurerVal; + dynamic selectedInsurer; + dynamic selectedEndorsementTypeVal; + + List> getInsurerDetailsData = []; + List> filteredInsurerData = []; + bool isLoadingA = false; String _formatDate(String rawDate) { try { @@ -227,7 +296,7 @@ class endosementState extends ConsumerState { } Future fetchEndorsementExcelReport() async { - final String searchValue = _searchStaffController.text; + final String searchValue = rightSearchController.text; final response = await apiService.generateEndorsementExcel(managerId,searchValue); // Map your controllers and IDs to the API parameters // final String fromDate = controllers['startDate']!.text; // "11-01-2025" @@ -251,6 +320,80 @@ class endosementState extends ConsumerState { // } } + 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; + }); + } + } + + Future getInsurerDetails() async { + setState(() => isLoadingA = true); + try { + final response = await apiService.fetchMasterDropDown('Insurers'); + + print("***999999999999999999*********** $response"); + + if (response['status'] == 200) { + print('getInsurerDetails - ${response['data']}'); + + setState(() { + getInsurerDetailsData = + List>.from(response['data']); + + filteredInsurerData = + List>.from(getInsurerDetailsData); + + print("Filtered Insurer Data: $filteredInsurerData"); + }); + } else { + setState(() { + getInsurerDetailsData = []; + filteredInsurerData = []; + }); + } + } catch (e) { + print('Error: $e'); + } finally { + setState(() => isLoadingA = false); + } + } + + Future loadEndorsementNumbers(String id) async { + // final response = await apiService.fetchEndorsementNumbers(id); + // + // if (response['status'] == 'success') { + // setState(() { + // endorsementNumbers = + // List>.from(response['data']); + // }); + // } + } + @override Widget build(BuildContext context) { return MainLayout( @@ -328,154 +471,17 @@ class endosementState extends ConsumerState { fontWeight: FontWeight.w400, ), ), - Spacer(), - ThemedSearchField( - hintText: 'Search', - backgroundColor: Color(0xFFFFFFFF), - txtHeight: 30, - // backgroundColor: Color(0xFFF6F8F8), - onChanged: filterData, - controller: _searchStaffController, - txtwidth: ResponsiveLayout.isMobile(context) - ? MediaQuery.of(context).size.width * 0.6 - : MediaQuery.of(context).size.width * 0.15, + ], + ), + ), + SizedBox(height: 10), + Container( + width: double.infinity, + child: Row( + children: [ + Expanded( + child: buildFilterBar(context), ), - - SizedBox(width: 10), - Tooltip( - message: 'Export Excel', - child: InkWell( - onTap: () async { - await fetchEndorsementExcelReport(); - }, - child: Container( - padding: const EdgeInsets.all(7.0), - decoration: BoxDecoration( - color: const Color(0xFF2E7D6E), - // color: const Color(0xFF425B5B), - borderRadius: BorderRadius.circular(8.0), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.asset( - "assets/miscellaneous/export.png", - height: 13, - width: 13, - ), - ], - ), - ), - ), - ), - // ExportBtn( - // sheetName: "Endorsement", - // fileName: "endorsement_list", - // data: filteredData, - // txt: !ResponsiveLayout.isMobile(context) - // ? true - // : false, - // displayHeaders: [ - // "S.No.", - // "Policy From.", - // "Status", - // "Vehicle.No.", - // "Insurer", - // "Policy No.", - // "Endorsement Type", - // "Endorsement No.", - // ], - // keys: [ - // "sno", // handled internally as i + 1 - // "policy_from", - // "status", - // "reg_no", - // "insurer_short_name", - // "policy_number", - // "endorsement_type_value", - // "endorsement_no", - // ], - // ), - SizedBox(width: 10), - InkWell( - onTap: () { - showDialog( - context: context, - builder: (ctx) => AddDialog( - managerId: managerId, - userId: userId, - role: roleId, - title: "Endorsement", - // policyNumber: '1', - // policyNumber: selectedPolicyNumber, - onSubmit: (value) { - debugPrint("New Endorsement: $value"); - // enrollKey.currentState?.getEndrosmentList(selectedPolicyNumber); - refresh(); - // Update claim list or call API - }, - ), - ); - }, - child: Container( - padding: EdgeInsets.all(4.8), - decoration: BoxDecoration( - color: const Color(0xFF2E7D6E), - borderRadius: BorderRadius.circular(8.0), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Tooltip( - message: 'Create Endorsement', - child: Icon( - Icons.add, - color: Colors.white, - size: 18, - ), - ), - ], - ), - ), - ), - // SizedBox(width: 10), - // GestureDetector( - // onTap: () { - // // print('Export'); - // }, - // child: Container( - // padding: EdgeInsets.all(8.0), - // decoration: BoxDecoration( - // color: Color(0xFF425B5B), - // borderRadius: BorderRadius.circular(8.0), - // ), - // child: Row( - // mainAxisSize: MainAxisSize.min, - // children: [ - // Icon(Icons.add, color: Colors.white), - // - // if (!ResponsiveLayout.isMobile(context)) ...[ - // SizedBox(width: 10), - // - // GestureDetector( - // onTap: () { - // // context.go(AppRoutes.agent / create); - // context.go('/staff/create'); - // }, - // child: Text( - // 'Create New Staff', - // style: GoogleFonts.inter( - // color: Colors.white, - // fontWeight: FontWeight.w600, - // fontSize: 14, - // ), - // ), - // ), - // ], - // ], - // ), - // ), - // ), ], ), ), @@ -494,40 +500,66 @@ class endosementState extends ConsumerState { child: Row( children: [ Expanded( - flex: 2, + flex: 1, child: Text('S No ', style: _headerStyle), ), Expanded( flex: 2, - child: Text('Policy From ', style: _headerStyle), + child: Text('Created Date ', style: _headerStyle), + ), + Expanded( + flex: 3, + child: Text('Endorsement Type ', style: _headerStyle), ), Expanded( flex: 2, - child: Text('Status ', style: _headerStyle), + child: Text('Vehicle No', style: _headerStyle), ), Expanded( flex: 2, - child: Text('Vehicle No ', style: _headerStyle), + child: Text('Insured Name', style: _headerStyle), + ), + Expanded( + flex: 3, + child: Text('Policy Number', style: _headerStyle), ), Expanded( flex: 2, - child: Text('Insurer', style: _headerStyle), - ), - Expanded( - flex: 2, - child: Text('Policy No ', style: _headerStyle), + child: Text('Start Date', style: _headerStyle), ), Expanded( flex: 2, child: Text( - 'Endorsement Type', + 'End Date', style: _headerStyle, ), ), Expanded( flex: 2, child: Text( - 'Endorsement No', + 'Insurer', + style: _headerStyle, + ), + ), + Expanded( + flex: 2, + child: Text( + 'Broker', + style: _headerStyle, + ), + ), + Expanded( + flex: 2, + child: Text( + 'Status', + style: _headerStyle, + ), + ), + // if(roleId == 'Accounts') + Expanded( + flex: 2, + child: Text( + 'Verification', style: _headerStyle, ), ), @@ -539,9 +571,25 @@ class endosementState extends ConsumerState { ), ), Expanded( - child: Container( - color: Colors.white, - child: _buildDataTable(context), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // MAIN TABLE + Expanded( + flex: 3, + child: Container( + // color: Colors.white, + child: _buildDataTable(context), + ), + ), + + // DRAWER (only if open) + // if (isDrawerOpen) + // Expanded( + // flex: 1, + // child: _buildDrawer(), + // ), + ], ), ), ], @@ -578,6 +626,79 @@ class endosementState extends ConsumerState { ); } + Widget buildFilterBar(BuildContext context) { + return SizedBox( + width: double.infinity, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE5E7EB)), + ), + child: Row( + children: [ + + /// 🔹 LEFT SIDE (SCROLLABLE FILTERS) + Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + buildStartDate(context), + const SizedBox(width: 12), + + buildEndDate(context), + const SizedBox(width: 12), + + buildEndorsementTypeSearch(context), + const SizedBox(width: 12), + + buildSelectInsurer(context), + const SizedBox(width: 12), + + buildStatusSearch(context), + const SizedBox(width: 12), + + buildVerificationSearch(context), + const SizedBox(width: 12), + + _iconButton(Icons.search, () { + refresh(); + }), + const SizedBox(width: 8), + + _iconButton(Icons.refresh, () { + startController.clear(); + endController.clear(); + selectedEndorsementTypeVal = null; + selectedInsurerVal = null; + selectedStatusVal = null; + selectedVerificationVal = null; + rightSearchController.clear(); + refresh(); + }), + ], + ), + ), + ), + + /// 🔹 RIGHT SIDE (FIXED) + const SizedBox(width: 20), + + _rightSearchField(), + const SizedBox(width: 12), + if(roleId != 'Accounts')...[ + _addButton(), + const SizedBox(width: 10), + ], + _exportButton(), + ], + ), + ), + ); + } + Widget _buildDataTable(BuildContext context) { if (filteredData.isEmpty) { return const SizedBox( @@ -614,108 +735,188 @@ class endosementState extends ConsumerState { } Widget _buildDataRow(Map item, sno) { - final String Id = item['id']?.toString() ?? ''; + final String id = item['id']?.toString() ?? ''; final String? pdfPath = item["endorsement_completion_file"]; final String? fileName = pdfPath != null && pdfPath.isNotEmpty ? pdfPath.split('/').last : null; - return Container( - padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 16), - // margin: const EdgeInsets.only(top: 10), - decoration: BoxDecoration( - color: Colors.white, - // color: Color(0xFFE0F7F9), - border: const Border( - bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1), - ), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Expanded(flex: 2, child: Text('$sno' ?? '-', style: _dataBold)), - Expanded(flex: 2, child: Text(item['policy_from'] ?? '-',style: _dataBold)), - Expanded(flex: 2, child: Text(item['status'] ?? '-',style: _dataBold)), - Expanded(flex: 2, child: Text(item['reg_no'] ?? '-',style: _dataBold)), - Expanded(flex: 2, child: Text(item['insurer_short_name'] ?? '-',style: _dataBold)), - Expanded(flex: 2, child: Text(item['policy_number'] ?? '-', style: _dataBold)), - Expanded(flex: 2, child: Text(item['endorsement_type_value'] ?? '-', style: _dataBold)), - Expanded(flex: 2, child: Text(item['endorsement_no'] ?? '-', style: _dataBold)), - Expanded( - flex: 2, // Action column - child: item['is_active'] == "1" - ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - constraints: const BoxConstraints(), - padding: EdgeInsets.zero, - icon: Image.asset("assets/miscellaneous/Edit.png", height: 15, width: 15), - onPressed: () { - showDialog( - context: context, - builder: (context) => UpdateEndorsementDialog( - item: item, - userId: userId, - managerId: managerId, - onSubmit: (val) => refresh(), - ), - ); - }, - ), - const SizedBox(width: 12), - InkWell( - onTap: () => apiService.downloadFile( - apiUrl: 'endorsement/downloadEndorsementCompletionFile?id=$Id', - apiId: Id, - localFile: null, - fileName: fileName, - ), - child: Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: Colors.green, - ), - child: const Icon(Icons.download, size: 14, color: Colors.white), - ), - ), - ], - ) - : const Text('-'), + + // final bool isSelected = selectedRow?['id']?.toString() == id; + // final bool isHovered = hoveredRowId == id; + // + // Color bgColor = Colors.white; + // + // if (isSelected) { + // bgColor = const Color(0xFFE6F4F1); // selected light teal + // } else if (isHovered) { + // bgColor = const Color(0xFFE6F4F1); // hover light grey + // } + + return MouseRegion( + cursor: SystemMouseCursors.click, + // onEnter: (_) { + // setState(() { + // hoveredRowId = id; + // }); + // }, + // onExit: (_) { + // setState(() { + // hoveredRowId = null; + // }); + // }, + child: GestureDetector( + onTap: () async { + setState(() { + selectedRow = item; + // isDrawerOpen = true; + }); + + await loadEndorsementNumbers(item['id']); + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 150), + padding: const EdgeInsets.symmetric( + vertical: 10, horizontal: 16), + decoration: BoxDecoration( + // color: bgColor, + border: const Border( + bottom: BorderSide( + color: Color(0xFFEAEAEA), + width: 1, + ), + ), ), - // 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), - // ), - // ), - // ), - // ], - // ), - // ], - // ), - // ), - ], + child: Row( + children: [ + Expanded(flex: 1, child: Text('$sno', style: _dataBold)), + + Expanded( + flex: 2, + child: Text( + item['created_at'] != null + ? item['created_at'].toString().split(' ')[0] + : '-', + style: _dataBold, + ), + ), + + Expanded( + flex: 3, + child: _buildBadge( + text: item['endorsement_type_value'], + type: 'endorsement', + ), + ), + + Expanded( + flex: 2, + child: Text(item['reg_no'] ?? '-', style: _dataBold)), + + Expanded( + flex: 2, + child: Text(item['insured_name'] ?? '-', style: _dataBold)), + + Expanded( + flex: 3, + child: + Text(item['policy_number'] ?? '-', style: _dataBold)), + + Expanded( + flex: 2, + child: Text(item['policy_start_date'] ?? '-', + style: _dataBold)), + + Expanded( + flex: 2, + child: Text(item['policy_end_date'] ?? '-', + style: _dataBold)), + + Expanded( + flex: 2, + child: Text(item['insurer_short_name'] ?? '-', + style: _dataBold)), + + Expanded( + flex: 2, + child: + Text(item['broker_name'] ?? '-', style: _dataBold)), + + Expanded( + flex: 2, + child: _buildBadge( + text: item['status'], + type: 'status', + ), + ), + // if(roleId == 'Accounts') + Expanded( + flex: 2, + child: _buildBadge( + text: item['is_data_accuracy_checked'] == '0' + ? 'To Verify' + : 'Verified', + type: 'verification', + ), + ), + + Expanded( + flex: 2, + child: item['is_active'] == "1" + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + constraints: const BoxConstraints(), + padding: EdgeInsets.zero, + icon: Image.asset( + "assets/miscellaneous/Edit.png", + height: 15, + width: 15), + onPressed: () async { + final result = await context.push( + AppRoutes.endorsomentValidation, + extra: { + "item": item, + "title": "Endorsement Validation", + "userId": userId, + "managerId": managerId, + "role": roleId, + }, + ); + if (result == true) { + refresh(); // 👈 reload list API + } + }, + ), + const SizedBox(width: 12), + InkWell( + onTap: () => + apiService.downloadFile( + apiUrl: + 'endorsement/downloadEndorsementCompletionFile?id=$id', + apiId: id, + localFile: null, + fileName: fileName, + ), + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(4), + color: Colors.green, + ), + child: const Icon(Icons.download, + size: 14, + color: Colors.white), + ), + ), + ], + ) + : const Text('-'), + ), + ], + ), + ), ), ); } @@ -879,6 +1080,839 @@ class endosementState extends ConsumerState { ); } + Widget _buildDrawer() { + return Container( + margin: const EdgeInsets.only(left: 12), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFEAEAEA)), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + + // HEADER + Container( + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide(color: Color(0xFFEAEAEA)), + ), + ), + child: Row( + children: [ + Expanded( + child: Text( + "${selectedRow?['reg_no']} - Endorsements", + style: _headerStyle, + ), + ), + IconButton( + icon: const Icon(Icons.close), + onPressed: () { + setState(() { + // isDrawerOpen = false; + selectedRow = null; + }); + }, + ), + ], + ), + ), + + // TABLE + Expanded( + child: endorsementNumbers.isEmpty + ? const Center(child: Text("No endorsement numbers")) + : ListView.builder( + itemCount: endorsementNumbers.length, + itemBuilder: (context, index) { + final item = endorsementNumbers[index]; + return Container( + padding: const EdgeInsets.all(12), + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: Color(0xFFEAEAEA), + ), + ), + ), + child: Row( + children: [ + Expanded( + child: Text( + item['endorsement_no'] ?? '-', + style: _dataBold, + ), + ), + IconButton( + icon: const Icon(Icons.edit, size: 16), + onPressed: () {}, + ), + IconButton( + icon: const Icon(Icons.download, size: 16), + onPressed: () {}, + ), + ], + ), + ); + }, + ), + ), + + // PAGINATION + PaginationControls( + currentPage: 1, + itemsPerPage: 10, + totalItems: endorsementNumbers.length, + onPageChanged: (page) {}, + onItemsPerPageChanged: (items) {}, + ), + ], + ), + ); + } + + Widget buildStartDate(BuildContext context) { + return SizedBox( + height: 36, + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.10, + child: ThemedDateField( + hintText: "Start Date", + controller: startController, + onDateSelected: (date) { + startController.text = + DateFormat('dd-MM-yyyy').format(date); + }, + ), + ); + } + + Widget buildEndDate(BuildContext context) { + return SizedBox( + height: 36, + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.10, + child: ThemedDateField( + hintText: "End Date", + controller: endController, + lastDate: DateTime.now(), + onDateSelected: (date) { + endController.text = + DateFormat('dd-MM-yyyy').format(date); + // refresh(); + }, + ), + ); + } + + Widget buildEndorsementTypeSearch(BuildContext context) { + final List> endorsementOptions = + List>.from(filteredEndrosmentData); + + Map? selectedItem; + + if (selectedEndorsementTypeVal != null && + selectedEndorsementTypeVal.toString().isNotEmpty && + endorsementOptions.isNotEmpty) { + try { + selectedItem = endorsementOptions.firstWhere( + (e) => + e['id'].toString() == + selectedEndorsementTypeVal.toString(), + ); + } catch (_) { + selectedItem = null; + } + } + + return SizedBox( + height: 33, + child: Container( + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.10, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color(0xFFE2E8F0)), + ), + child: DropdownSearch>( + selectedItem: selectedItem, + + items: (filter, infiniteScrollProps) { + if (filter.isEmpty) return endorsementOptions; + + return endorsementOptions + .where((item) => item['endorsement_type'] + .toString() + .toLowerCase() + .contains(filter.toLowerCase())) + .toList(); + }, + + itemAsString: (item) => + item['endorsement_type']?.toString() ?? '', + + compareFn: (item, selected) { + if (selected == null) return false; + return item['id'].toString() == + selected['id'].toString(); + }, + + dropdownBuilder: (context, selectedItem) { + return Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['endorsement_type'] + .toString() + : '', + style: GoogleFonts.poppins( + fontSize: 11, + color: Colors.black, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ); + }, + + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Endorsement Type", + ).copyWith( + filled: true, + fillColor: Colors.white, + isDense: true, + contentPadding: + const EdgeInsets.symmetric( + horizontal: 5, + vertical: 1, + ), + ), + ), + + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 300, + minWidth: ResponsiveLayout.isMobile(context) + ? 200 + : MediaQuery.of(context).size.width * 0.15, + ), + menuProps: + const MenuProps(backgroundColor: Colors.white), + ), + + onChanged: (val) { + if (val == null) return; + + selectedEndorsementTypeVal = val['id']; + // refresh(); + }, + ), + ), + ); + } + + Widget buildSelectInsurer(BuildContext context) { + // Ensure this list has data BEFORE building dropdown + final List> insurerOptions = + List>.from(filteredInsurerData); + + // Selected item logic + Map? selectedItem; + + if (selectedInsurerVal != null && + selectedInsurerVal.toString().isNotEmpty && + insurerOptions.isNotEmpty) { + try { + selectedItem = insurerOptions.firstWhere( + (e) => e['id'].toString() == selectedInsurerVal.toString(), + ); + } catch (e) { + selectedItem = null; + } + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 33, + child: Container( + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.10, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10 ), + border: Border.all(color: const Color(0xFFE2E8F0)), + ), + child: DropdownSearch>( + selectedItem: selectedItem, + + // FILTER LOGIC: This filters the list as the user types + items: (filter, infiniteScrollProps) { + if (filter.isEmpty) { + return insurerOptions; + } + return insurerOptions + .where((item) => item['short_name'] + .toString() + .toLowerCase() + .contains(filter.toLowerCase())) + .toList(); + }, + + itemAsString: (item) => item['short_name']?.toString() ?? '', + + compareFn: (item, selected) { + if (selected == null) return false; + return item['id'].toString() == selected['id'].toString(); + }, + + // FIELD UI (The collapsed state) + dropdownBuilder: (context, selectedItem) { + return Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['short_name'].toString() + : '', + style: GoogleFonts.poppins( + fontSize: 11, + color: Colors.black, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ); + }, + + decoratorProps: DropDownDecoratorProps( + decoration: AppInputDecorations.dropdownDecoration( + label: "Select Insurer", + ).copyWith( + filled: true, + fillColor: Colors.white, + isDense: true, + contentPadding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 1, + ), + ), + ), + + // POPUP UI (The expanded state with search) + popupProps: PopupProps.menu( + showSearchBox: true, // Enabled searching + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 300, + minWidth: ResponsiveLayout.isMobile(context) + ? 200 + : MediaQuery.of(context).size.width * 0.10, + ), + menuProps: const MenuProps(backgroundColor: Colors.white), + + // Customizing the search field appearance + searchFieldProps: TextFieldProps( + style: GoogleFonts.poppins(fontSize: 13), + decoration: InputDecoration( + hintText: "Search insurer...", + hintStyle: GoogleFonts.poppins(fontSize: 12), + contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + ), + ), + + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 10, + ), + decoration: BoxDecoration( + color: isSelected ? Colors.blue.withOpacity(0.1) : Colors.transparent, + ), + child: Text( + item['short_name'].toString(), + style: GoogleFonts.inter( + fontSize: 13, + color: Colors.black, + ), + ), + ); + }, + ), + + // ON CHANGE + onChanged: (val) { + if (val == null) return; + + selectedInsurerVal = val['id']; + // refresh(); + }, + ), + ), + ), + ], + ); + } + + Widget buildStatusSearch(BuildContext context) { + final List> statusOptions = [ + {'id': 3, 'status': 'All'}, + {'id': 1, 'status': 'Open'}, + {'id': 2, 'status': 'Closed'}, + ]; + + Map? selectedItem; + + if (selectedStatusVal != null) { + try { + selectedItem = statusOptions.firstWhere( + (e) => e['status'] == selectedStatusVal, + ); + } catch (_) { + selectedItem = null; + } + } + + return SizedBox( + height: 33, + child: Container( + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.10, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color(0xFFE2E8F0)), + ), + child: DropdownSearch>( + selectedItem: selectedItem, + items: (filter, infiniteScrollProps) => statusOptions, + + itemAsString: (val) => val['status'].toString(), + + compareFn: (item, selected) { + if (selected == null) return false; + return item['id'] == selected['id']; + }, + + dropdownBuilder: (context, selectedItem) { + return Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['status'].toString() + : '', + style: GoogleFonts.poppins( + fontSize: 11, + color: Colors.black, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ); + }, + + decoratorProps: DropDownDecoratorProps( + decoration: AppInputDecorations.dropdownDecoration( + label: "Select Status", + ).copyWith( + filled: true, + fillColor: Colors.white, + isDense: true, + contentPadding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 1, + ), + ), + ), + + popupProps: PopupProps.menu( + showSearchBox: false, + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 300, + minWidth: ResponsiveLayout.isMobile(context) + ? 200 + : MediaQuery.of(context).size.width * 0.10, + ), + menuProps: const MenuProps(backgroundColor: Colors.white), + ), + + onChanged: (val) { + if (val == null) return; + + selectedStatusVal = val['status']; + // refresh(); + }, + ), + ), + ); + } + + Widget buildVerificationSearch(BuildContext context) { + final List> verificationOptions = [ + {'id': 2, 'status': 'All'}, + {'id': 0, 'status': 'To Verify'}, + {'id': 1, 'status': 'Verified'}, + ]; + + Map? selectedItem; + + if (selectedVerificationVal != null) { + try { + selectedItem = verificationOptions.firstWhere( + (e) => e['id'] == selectedVerificationVal, + ); + } catch (_) { + selectedItem = null; + } + } + + return SizedBox( + height: 33, + child: Container( + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.10, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: const Color(0xFFE2E8F0)), + ), + child: DropdownSearch>( + selectedItem: selectedItem, + items: (filter, infiniteScrollProps) => verificationOptions, + + itemAsString: (val) => val['status'].toString(), + + compareFn: (item, selected) { + if (selected == null) return false; + return item['id'] == selected['id']; + }, + + dropdownBuilder: (context, selectedItem) { + return Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['status'].toString() + : '', + style: GoogleFonts.poppins( + fontSize: 11, + color: Colors.black, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ); + }, + + decoratorProps: DropDownDecoratorProps( + decoration: AppInputDecorations.dropdownDecoration( + label: "Select Verification", + ).copyWith( + filled: true, + fillColor: Colors.white, + isDense: true, + contentPadding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 1, + ), + ), + ), + + popupProps: PopupProps.menu( + showSearchBox: false, + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 300, + minWidth: ResponsiveLayout.isMobile(context) + ? 200 + : MediaQuery.of(context).size.width * 0.10, + ), + menuProps: const MenuProps(backgroundColor: Colors.white), + ), + + onChanged: (val) { + if (val == null) return; + + selectedVerificationVal = val['id']; + // refresh(); + }, + ), + ), + ); + } + + Widget _iconButton( + IconData icon, VoidCallback? onTap) { + return InkWell( + onTap: onTap, + child: Container( + width: 36, + height: 36, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: const Color(0xFFE5E7EB)), + color: Colors.white, + ), + child: Icon(icon, + size: 18, color: Colors.grey[700]), + ), + ); + } + + Widget _rightSearchField() { + return Container( + width: 220, + height: 36, + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all(color: const Color(0xFFE5E7EB)), + color: Colors.white, + ), + child: Row( + children: [ + const Icon(Icons.search, size: 18, color: Colors.grey), + const SizedBox(width: 8), + Expanded( + child: TextField( + controller: rightSearchController, + decoration: InputDecoration( + hintText: "Search...", + border: InputBorder.none, + isDense: true, + hintStyle: GoogleFonts.poppins(fontSize: 11), + ), + style: GoogleFonts.poppins(fontSize: 11), + onChanged: (val) { + filterData(val); + }, + ), + ), + ], + ), + ); + } + + Widget _exportButton() { + return InkWell( + onTap: () async { + await fetchEndorsementExcelReport(); + }, + child: Container( + width: 40, + height: 36, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: const Color(0xFF2E7D6E), + ), + child:Tooltip( + message: 'Export', + child: Image.asset( + "assets/miscellaneous/export.png", + height: 13, + width: 13, + ), + ), + ), + ); + } + + Widget _addButton() { + return InkWell( + onTap: () async { + showDialog( + context: context, + builder: (ctx) { + final screenWidth = MediaQuery.of(ctx).size.width; + + double dialogWidth; + + if (screenWidth > 1400) { + dialogWidth = 1200; + } else if (screenWidth > 1100) { + dialogWidth = 1000; + } else if (screenWidth > 900) { + dialogWidth = 850; + } else { + dialogWidth = screenWidth * 0.95; // mobile/tablet + } + + return Center( + child: SizedBox( + width: dialogWidth, + child: CreateEndorsementDialog( + managerId: managerId, + userId: userId, + role: roleId, + title: "Endorsement", + onSubmit: (value) { + debugPrint("New Endorsement: $value"); + refresh(); + }, + ), + ), + ); + }, + ); + }, + child: Container( + width: 40, + height: 36, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: const Color(0xFF2E7D6E), + ), + child: const Tooltip( + message: 'Create Endorsement', + child: Icon( + Icons.add, + color: Colors.white, + size: 18, + ), + ), + ), + ); + } + + // Widget _editButton(item) { + // return InkWell( + // onTap: () async { + // showDialog( + // context: context, + // builder: (ctx) { + // final screenWidth = MediaQuery.of(ctx).size.width; + // + // double dialogWidth; + // + // if (screenWidth > 1400) { + // dialogWidth = 1200; + // } else if (screenWidth > 1100) { + // dialogWidth = 1000; + // } else if (screenWidth > 900) { + // dialogWidth = 850; + // } else { + // dialogWidth = screenWidth * 0.95; // mobile/tablet + // } + // + // return Center( + // child: SizedBox( + // width: dialogWidth, + // child: endorsomentUpdateValidation( + // item:item, + // managerId: managerId, + // userId: userId, + // role: roleId, + // title: "Endorsement", + // onSubmit: (value) { + // debugPrint("New Endorsement: $value"); + // refresh(); + // }, + // ), + // ), + // ); + // }, + // ); + // }, + // child: Container( + // width: 40, + // height: 36, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(8), + // color: const Color(0xFF2E7D6E), + // ), + // child: const Tooltip( + // message: 'Create Endorsement', + // child: Icon( + // Icons.add, + // color: Colors.white, + // size: 18, + // ), + // ), + // ), + // ); + // } + + Widget _buildBadge({ + required String? text, + required String type, + }) { + String value = text ?? '-'; + + Color bgColor = Colors.grey.shade200; + Color textColor = Colors.black87; + + // 🔹 STATUS COLORS + if (type == 'status') { + switch (value) { + case 'Open': + bgColor = const Color(0xFFFDECC8); + textColor = const Color(0xFFB45309); + break; + + case 'Closed': + bgColor = const Color(0xFFD1FADF); + textColor = const Color(0xFF067647); + break; + } + } + + // 🔹 VERIFICATION COLORS + else if (type == 'verification') { + switch (value) { + case 'To Verify': + bgColor = const Color(0xFFE0EAFF); + textColor = const Color(0xFF1D4ED8); + break; + + case 'Verified': + bgColor = const Color(0xFFD1FADF); + textColor = const Color(0xFF067647); + break; + } + } + + // 🔹 ENDORSEMENT TYPE COLORS (Purple Style) + else if (type == 'endorsement') { + bgColor = const Color(0xFFEDE9FE); // light purple + textColor = const Color(0xFF6D28D9); // purple + } + + return Align( + alignment: Alignment.centerLeft, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 5, + ), + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(20), + ), + child: Text( + value, + style: GoogleFonts.inter( + fontSize: 11, + fontWeight: FontWeight.w500, + color: textColor, + ), + ), + ), + ); + } + + static final _dataBold = GoogleFonts.inter( fontSize: 11, diff --git a/lib/presentation/screens/UserManagement/Agent/agentList.dart b/lib/presentation/screens/UserManagement/Agent/agentList.dart index 687f376..e58b51a 100644 --- a/lib/presentation/screens/UserManagement/Agent/agentList.dart +++ b/lib/presentation/screens/UserManagement/Agent/agentList.dart @@ -327,8 +327,8 @@ class AgentListState extends ConsumerState { 'Partner Id', 'Partner Name', 'Email', + 'Sales Executive Name', 'Phone Number', - 'Retention Rate', 'Address', 'Status', @@ -338,6 +338,7 @@ class AgentListState extends ConsumerState { "agent_code", "name", "email", + "sales_executive_name", "mobile", "retention_rate", "address", diff --git a/lib/presentation/screens/staff/policy/policy_validation.dart b/lib/presentation/screens/staff/policy/policy_validation.dart index 370d81d..803f8c8 100644 --- a/lib/presentation/screens/staff/policy/policy_validation.dart +++ b/lib/presentation/screens/staff/policy/policy_validation.dart @@ -444,6 +444,41 @@ class _policyValidationState extends ConsumerState { } } + Future getPaymentMode() async { + setState(() => isLoadingPaymentMode = true); + + try { + final response = await apiService.fetchMasterDropDown('PaymentMode'); + + if (response['status'] == 200 && response['data'] != null) { + final allData = List>.from(response['data']); + final activePaymentMode = + allData.where((item) => item['is_active'] == "1").toList(); + + setState(() { + getPaymentModeData = activePaymentMode; + filteredPaymentModeData = List.from(getPaymentModeData); + + // ✅ IMPORTANT: rebind selected value AFTER list is ready + if (selectedPaymentMode != null && + selectedPaymentMode!.isNotEmpty && + selectedPaymentMode != '0') { + // nothing else needed – rebuild is enough + } + }); + } else { + // setState(() { + getPaymentModeData.clear(); + filteredPaymentModeData.clear(); + // }); + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() => isLoadingPaymentMode = false); + } + } + Future getInsurancPlanType() async { print('getInsurancPlanType called'); setState(() { @@ -478,41 +513,6 @@ class _policyValidationState extends ConsumerState { } } - Future getPaymentMode() async { - setState(() => isLoadingPaymentMode = true); - - try { - final response = await apiService.fetchMasterDropDown('PaymentMode'); - - if (response['status'] == 200 && response['data'] != null) { - final allData = List>.from(response['data']); - final activePaymentMode = - allData.where((item) => item['is_active'] == "1").toList(); - - setState(() { - getPaymentModeData = activePaymentMode; - filteredPaymentModeData = List.from(getPaymentModeData); - - // ✅ IMPORTANT: rebind selected value AFTER list is ready - if (selectedPaymentMode != null && - selectedPaymentMode!.isNotEmpty && - selectedPaymentMode != '0') { - // nothing else needed – rebuild is enough - } - }); - } else { - // setState(() { - getPaymentModeData.clear(); - filteredPaymentModeData.clear(); - // }); - } - } catch (e) { - print('Exception occurred: $e'); - } finally { - setState(() => isLoadingPaymentMode = false); - } - } - Future getEnquiryVehicleTypeForCommission() async { diff --git a/lib/presentation/widgets/drawer_menu.dart b/lib/presentation/widgets/drawer_menu.dart index a1e6419..34acbad 100644 --- a/lib/presentation/widgets/drawer_menu.dart +++ b/lib/presentation/widgets/drawer_menu.dart @@ -59,7 +59,7 @@ class DrawerMenuState extends ConsumerState { const SizedBox(height: 5), _buildPopupItem( label: "Endorsement", - onTap: () => context.go(AppRoutes.endosement), + onTap: () => context.go(AppRoutes.Endorsement), ), const SizedBox(height: 5), _buildPopupItem( diff --git a/lib/presentation/widgets/drawer_menu1.dart b/lib/presentation/widgets/drawer_menu1.dart index 34f82cd..16f1067 100644 --- a/lib/presentation/widgets/drawer_menu1.dart +++ b/lib/presentation/widgets/drawer_menu1.dart @@ -63,7 +63,7 @@ class DrawerMenuState extends ConsumerState { const SizedBox(height: 5), _buildPopupItem( label: "Endorsement", - onTap: () => context.go(AppRoutes.endosement), + onTap: () => context.go(AppRoutes.Endorsement), ), const SizedBox(height: 5), _buildPopupItem( diff --git a/lib/presentation/widgets/mobile_tabs.dart b/lib/presentation/widgets/mobile_tabs.dart index d9ad406..8d90d0f 100644 --- a/lib/presentation/widgets/mobile_tabs.dart +++ b/lib/presentation/widgets/mobile_tabs.dart @@ -71,7 +71,7 @@ class _MobileBottomMenuState extends ConsumerState { // Reports tapped → show bottom sheet _showOptionsSheet([ {'label': 'Claims', 'route': AppRoutes.claimlist}, - {'label': 'Endorsement', 'route': AppRoutes.endosement}, + {'label': 'Endorsement', 'route': AppRoutes.Endorsement}, {'label': 'Policy', 'route': AppRoutes.policylist}, ]); break; diff --git a/pubspec.lock b/pubspec.lock index d77ec7b..abbeba9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -700,26 +700,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -1297,10 +1297,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" toastification: dependency: "direct main" description: @@ -1417,10 +1417,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: diff --git a/web/index.html b/web/index.html index 91b032b..725e5f9 100644 --- a/web/index.html +++ b/web/index.html @@ -15,8 +15,8 @@ the `--base-href` argument provided to `flutter build`. --> - - + +