From fcdc9da6095d8a435cd6782232b1bc3a7da8c17a Mon Sep 17 00:00:00 2001 From: venbaittech Date: Mon, 1 Dec 2025 14:57:35 +0530 Subject: [PATCH] quick_proceed status_changes --- .flutter-plugins-dependencies | 2 +- lib/core/routing/app_router.dart | 6 + lib/core/routing/routes.dart | 1 + lib/core/services/api_service.dart | 19 + lib/presentation/layouts/appheader.dart | 4 +- lib/presentation/layouts/main_layout.dart | 7 +- .../Proposal_QuickCreation.dart | 915 ++-- .../staff/Enquiry/enquiry_inline_dec1.dart | 4696 +++++++++++++++++ .../staff/Enquiry/enquiry_inline_list.dart | 734 ++- .../screens/staff/Enquiry/raise_enq_form.dart | 42 +- .../screens/staff/Enquiry/staff_policy.dart | 3039 +++++++++++ .../themes/indicators/side_Drawer_Panel.dart | 2 +- .../text_field_theme_inline_editor.dart | 15 +- 13 files changed, 8893 insertions(+), 589 deletions(-) create mode 100644 lib/presentation/screens/staff/Enquiry/enquiry_inline_dec1.dart create mode 100644 lib/presentation/screens/staff/Enquiry/staff_policy.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 2dee264..dd71b39 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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","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.1.0/","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":"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":"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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","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.30/","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.0.5/","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.18/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.12/","native_build":true,"dependencies":[],"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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","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.1.0/","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":"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":"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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","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":"url_launcher_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","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":"url_launcher_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","dependencies":[],"dev_dependency":false},{"name":"firebase_app_check_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check_web-0.2.0+16/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_auth_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth_web-6.0.2/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core_web-3.1.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.0.1/","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.0.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":"shared_preferences_web","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","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":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_app_check","dependencies":["firebase_app_check_web","firebase_core"]},{"name":"firebase_app_check_web","dependencies":["firebase_core","firebase_core_web"]},{"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":"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":"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":"2025-11-28 18:59:48.448938","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":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","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.1.0/","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":"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":"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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","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.30/","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.0.5/","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.18/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.12/","native_build":true,"dependencies":[],"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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","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.1.0/","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":"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":"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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","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":"url_launcher_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","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":"url_launcher_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","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":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","dependencies":[],"dev_dependency":false},{"name":"firebase_app_check_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check_web-0.2.0+16/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_auth_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth_web-6.0.2/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core_web-3.1.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.0.1/","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.0.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":"shared_preferences_web","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","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":"file_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"firebase_app_check","dependencies":["firebase_app_check_web","firebase_core"]},{"name":"firebase_app_check_web","dependencies":["firebase_core","firebase_core_web"]},{"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":"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":"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":"2025-12-01 14:39:08.957318","version":"3.32.1","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/lib/core/routing/app_router.dart b/lib/core/routing/app_router.dart index 88c5e2a..97c2374 100644 --- a/lib/core/routing/app_router.dart +++ b/lib/core/routing/app_router.dart @@ -30,6 +30,7 @@ import '../../presentation/screens/splash/splash_screen.dart'; import '../../presentation/screens/staff/Enquiry/enquiry_inline_Edit_17Nov.dart'; import '../../presentation/screens/staff/Enquiry/enquiry_inline_list.dart'; import '../../presentation/screens/staff/Enquiry/enquiry_list.dart'; +import '../../presentation/screens/staff/Enquiry/staff_policy.dart'; import '../../presentation/screens/staff/policy/policy.dart'; import '../../presentation/screens/staff/policy/policy_list.dart'; import '../../presentation/screens/staff/quotations/quotation.dart'; @@ -176,6 +177,11 @@ final GoRouter appRouter = GoRouter( builder: (context, state) => const PolicyScreen(), ), + GoRoute( + path: AppRoutes.policyStaffEnq, + builder: (context, state) => PolicyStaffEnqList(), + ), + GoRoute( path: AppRoutes.enquiryForStaff, builder: (context, state) => const EnquiryListStaffInline(), diff --git a/lib/core/routing/routes.dart b/lib/core/routing/routes.dart index 704569d..2fb2a3a 100644 --- a/lib/core/routing/routes.dart +++ b/lib/core/routing/routes.dart @@ -21,6 +21,7 @@ class AppRoutes { static const String policylist = '/policylist'; static const String quotation = '/QuotationScreen'; static const String policy = '/PolicyScreen'; + static const String policyStaffEnq = '/policyStaffEnq'; static const String payout = '/payout'; static const String invoiceList = '/invoiceList'; diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 9d3b57e..d67100d 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -576,6 +576,8 @@ class ApiService { Future> fetchStaffUserList(int managerId, role) async { // print(_token); + + print('rolemanagerId - $managerId'); if (_token == null) { await _initializeToken(); } @@ -587,6 +589,7 @@ class ApiService { dynamic url; if (role == 'manager') { print('manager'); + // url = Uri.parse('${Env.apiUrl}staff/staffList'); url = Uri.parse('${Env.apiUrl}staff/staffList?manager_id=${managerId}'); } else { print('handler'); @@ -770,6 +773,22 @@ class ApiService { return response; } + Future> updateEnquiryInProgress(id) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + final url = Uri.parse( + '${Env.apiUrl}enquiry/updateEnquiryInProgress?enquiry_id=$id', + ); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'app-signature': Env.App_Signature, + }; + final response = await _makeGetRequest(url, headers); + return response; + } + Future> findEnqQuotePolicyView(id) async { print('findEnqQuotePolicyVie2w - $id'); if (_token == null) { diff --git a/lib/presentation/layouts/appheader.dart b/lib/presentation/layouts/appheader.dart index 80ac54f..0f81416 100644 --- a/lib/presentation/layouts/appheader.dart +++ b/lib/presentation/layouts/appheader.dart @@ -384,11 +384,11 @@ class _AppHeaderState extends ConsumerState { onPressed: () { SideDrawerPanel.show( context: context, - title: 'Proposal Creation', + title: 'Quote Creation', child: CreateProposal_Quick(), ); }, - tooltip: 'Create Proposal', + tooltip: 'Quick Quote', ), ), diff --git a/lib/presentation/layouts/main_layout.dart b/lib/presentation/layouts/main_layout.dart index af08ca8..ca75fde 100644 --- a/lib/presentation/layouts/main_layout.dart +++ b/lib/presentation/layouts/main_layout.dart @@ -135,7 +135,12 @@ class MainLayoutState extends ConsumerState { // debugPrint("Notifications tapped"); // }, // ), - appBar: AppHeader(), + // appBar: AppHeader(), + appBar: PreferredSize( + preferredSize: AppHeader().preferredSize, + child: ExcludeFocus(child: AppHeader()), + ), + body: Row( children: [ // AnimatedContainer( diff --git a/lib/presentation/screens/staff/Enquiry/Proposal_QuickCreation/Proposal_QuickCreation.dart b/lib/presentation/screens/staff/Enquiry/Proposal_QuickCreation/Proposal_QuickCreation.dart index 8093ec9..131799b 100644 --- a/lib/presentation/screens/staff/Enquiry/Proposal_QuickCreation/Proposal_QuickCreation.dart +++ b/lib/presentation/screens/staff/Enquiry/Proposal_QuickCreation/Proposal_QuickCreation.dart @@ -97,6 +97,8 @@ class CreateProposal_QuickFormState List tabHeader = ['idv', 'premium_Amount', 'insurer', 'regNo']; + late FocusNode partnerFocusNode; + List rows = []; List> getBrokerData = []; @@ -125,6 +127,8 @@ class CreateProposal_QuickFormState dynamic userId; dynamic managerId; + bool isSingleSave = false; + List> quotationList = []; Map quotationData() { @@ -153,7 +157,8 @@ class CreateProposal_QuickFormState // "vehicle_type_id": selectedVehicleType, "is_quick_quote": "1", - "quotation": quotationList, + // "quotation": quotationList, + "quotation": jsonEncode(quotationList), // "is_data_created_by_handler": roleId == 'handler' ? '1' : '0', // "is_data_created_by_manager": roleId == 'manager' ? '1' : '0', "is_data_created_by_staff": roleId != null ? '1' : '0', @@ -163,6 +168,7 @@ class CreateProposal_QuickFormState // "previous_policy_file_name": "previous_policy.pdf", "remarks": controllers["remarks"]?.text, // "assigned_to": (roleId == 'staff') ? userId : selectedStaff, + "assigned_to": userId, "insurer_id": selectedInsurer, "broker_id": selectedBroker, "manager_id": managerId, @@ -179,6 +185,7 @@ class CreateProposal_QuickFormState for (String field in tabHeader) { controllers[field] = TextEditingController(); } + partnerFocusNode = FocusNode(); Future.microtask(() async { roleId = ref.read(userRoleProvider); @@ -212,6 +219,7 @@ class CreateProposal_QuickFormState // Dispose all TextEditingControllers for (var controller in controllers.values) { controller.dispose(); + partnerFocusNode.dispose(); } super.dispose(); } @@ -495,6 +503,10 @@ class CreateProposal_QuickFormState dropDownKeyInsurerEnqAsgn.currentState?.changeSelectedItem(null); dropDownKey.currentState?.changeSelectedItem(null); }); + + if (isSingleSave) { + handleDone(); + } } } @@ -533,6 +545,14 @@ class CreateProposal_QuickFormState dataDetails(); final dataSet = dataDetails(); print("dataSetAgent - $dataSet"); + + if (quotationList.isEmpty) { + print("Please add at least one quotation before saving."); + // You can also show a snackbar or dialog + ToastHelper.showErrorToast(context, 'Add atleast one proposal'); + return; // ❌ stop execution + } + // print("managerId - $managerId ,userId - $userId "); createUserData(dataSet); } else { @@ -567,11 +587,23 @@ class CreateProposal_QuickFormState print("USerDAta - $userData"); + // userData.forEach((key, value) { + // // if (key != 'certificate_file_name') { + // request.fields[key] = value.toString(); + // print("✅ Encoded $key: ${request.fields[key]}"); + // // } + // }); + userData.forEach((key, value) { - // if (key != 'certificate_file_name') { - request.fields[key] = value.toString(); - print("✅ Encoded $key: ${request.fields[key]}"); - // } + if (value is List || value is Map) { + // List, Map → convert to JSON + request.fields[key] = jsonEncode(value); + } else { + // normal value + request.fields[key] = value?.toString() ?? ""; + } + + print("➡ $key: ${request.fields[key]}"); }); if (docUploadedFile != null) { @@ -612,7 +644,8 @@ class CreateProposal_QuickFormState print("Response: ${response.body}"); // ToastHelper.showErrorToast(context, 'Proposal Created'); reset(); - Navigator.of(context).pop(); + getQuickQuotationList(managerId); + // Navigator.of(context).pop(); } else if (response.statusCode == 403) { await apiService.clearLocalStorageAndRedirect(); } else { @@ -628,10 +661,70 @@ class CreateProposal_QuickFormState } } + Future handleProceed(val, id) async { + print('handleProceed -1 '); + final String apiUrldata; + apiUrldata = '${Env.apiUrl}quotation/acceptOrRejectQuotation'; + + // final token = await getToken(); // Fetch token + print('handleProceed -2 '); + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + final Map data = { + "id": id, + // "status": 'Accepted', + "status": val, + "action_by": userId, + // "action_user": (role == 'agent') ? 'agent' : 'handler', + "action_user": roleId, + }; + print('handleProceed -3 '); + // data['id'] = selectedId; // Add plan_id for update + // data['status'] = val; + + print("data------- $data"); + + try { + final response = await http.post( + Uri.parse(apiUrldata), + headers: { + 'Authorization': 'Bearer $_token', + 'Content-Type': 'application/json', + 'app-signature': Env.App_Signature, + }, + body: jsonEncode(data), // Convert map to JSON + ); + + if (response.statusCode == 200) { + print("Response: ${response.body}"); + + ToastHelper.showSuccessToast(context, 'Status Updated'); + print("tre1"); + selectedId = null; // just update field + Navigator.of(context).pop(); + + context.go('/enquiryForStaff'); + print("tre11"); + getQuickQuotationList(managerId); + } else if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + } else { + final responseBody = jsonDecode(response.body); + dynamic msg = responseBody['data']; + ToastHelper.showErrorToast(context, 'Status Updation Failed'); + print("Failed to submit plan. Status: ${response.statusCode}"); + print("Error: ${response.body}"); + } + } catch (e) { + print(" Error submitting Staff: $e"); + } + } + @override Widget build(BuildContext context) { - return Form( - key: _formKey, + return FocusTraversalGroup( child: Column( children: [ Container( @@ -651,194 +744,248 @@ class CreateProposal_QuickFormState ), borderRadius: BorderRadius.circular(8.0), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - buildAgentName(context), - const SizedBox(width: 20), - buildVehicleNumber(context), - ], - ), - Divider(thickness: 0.3, color: Colors.blueGrey.shade100), - SizedBox(height: 2), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - buildInsurer(context), - const SizedBox(width: 20), - buildInsurancePlanType(context), - const SizedBox(width: 20), - buildPremiumAmnt(context), - const SizedBox(width: 10), - Row( - children: [ - GestureDetector( - onTap: () { - addQuotationRow(); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 2, - vertical: 2, + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + buildAgentName(context), + const SizedBox(width: 20), + buildVehicleNumber(context), + ], + ), + + Divider(thickness: 0.3, color: Colors.blueGrey.shade100), + SizedBox(height: 2), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + buildInsurer(context), + const SizedBox(width: 20), + buildInsurancePlanType(context), + const SizedBox(width: 20), + buildPremiumAmnt(context), + const SizedBox(width: 10), + Row( + children: [ + // SizedBox(width: 10), + // GestureDetector( + // onTap: () { + // setState(() { + // isSingleSave = true; + // }); + // addQuotationRow(); + // }, + // child: Container( + // padding: const EdgeInsets.symmetric( + // horizontal: 5, + // vertical: 5, + // ), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(5.0), + // color: Colors.blue, + // ), + // child: Text( + // 'Save', + // style: GoogleFonts.poppins( + // color: Colors.white, + // fontSize: 10, + // ), + // ), + // ), + // ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), - color: Colors.blue, - ), - child: Icon( - Icons.add, - color: Colors.white, - size: 14, + onPressed: () { + setState(() { + isSingleSave = true; + }); + addQuotationRow(); + }, + child: Text( + 'Save', + style: GoogleFonts.poppins( + color: Colors.white, + fontSize: 10, + ), ), ), - ), - ], - ), - ], - ), - - if (quotationList.isNotEmpty) ...[ - const SizedBox(height: 10), - - Text( - 'Added Proposal (${quotationList.length})', - style: GoogleFonts.poppins( - fontSize: 12, - color: Color(0xFF334155), - ), + SizedBox(width: 10), + GestureDetector( + onTap: () { + addQuotationRow(); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + color: Colors.blue, + ), + child: Icon( + Icons.add, + color: Colors.white, + size: 14, + ), + ), + ), + ], + ), + ], ), - const SizedBox(height: 10), - GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: quotationList.length, - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, // 👈 3 cards per row - mainAxisSpacing: 16, - crossAxisSpacing: 16, - childAspectRatio: - 3, // 👈 controls card shape (adjust if needed) - ), - itemBuilder: (context, index) { - final item = quotationList[index]; - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE2E8F0)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 1, - offset: const Offset(0, 1), - ), - ], - ), - child: Stack( - children: [ - /// 🟦 Card Content - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item["insurer_name"], - style: GoogleFonts.poppins( - fontSize: 11, - fontWeight: FontWeight.w600, - color: Color(0xFF334155), + if (quotationList.isNotEmpty) ...[ + const SizedBox(height: 10), + + Text( + 'Added Quote(${quotationList.length})', + style: GoogleFonts.poppins( + fontSize: 12, + color: Color(0xFF334155), + ), + ), + const SizedBox(height: 10), + GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: quotationList.length, + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, // 👈 3 cards per row + mainAxisSpacing: 16, + crossAxisSpacing: 16, + childAspectRatio: + 3, // 👈 controls card shape (adjust if needed) + ), + itemBuilder: (context, index) { + final item = quotationList[index]; + + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: const Color(0xFFE2E8F0)), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 1, + offset: const Offset(0, 1), + ), + ], + ), + child: Stack( + children: [ + /// 🟦 Card Content + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item["insurer_name"], + style: GoogleFonts.poppins( + fontSize: 11, + fontWeight: FontWeight.w600, + color: Color(0xFF334155), + ), ), - ), - const SizedBox(height: 6), + const SizedBox(height: 6), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - item["plan_type_name"], - style: GoogleFonts.poppins( - fontSize: 11, - fontWeight: FontWeight.w400, - color: Colors.black, + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + item["plan_type_name"], + style: GoogleFonts.poppins( + fontSize: 11, + fontWeight: FontWeight.w400, + color: Colors.black, + ), ), - ), - Text( - "₹${item["premium_amount"].toString().replaceAll("\$", "")}", - style: GoogleFonts.poppins( - fontSize: 11, - fontWeight: FontWeight.w400, - color: Colors.blueGrey, + Text( + "₹${item["premium_amount"].toString().replaceAll("\$", "")}", + style: GoogleFonts.poppins( + fontSize: 11, + fontWeight: FontWeight.w400, + color: Colors.blueGrey, + ), ), - ), - ], - ), - ], - ), + ], + ), + ], + ), - /// ❌ Delete Icon - Positioned( - top: 0, - right: 0, - child: GestureDetector( - onTap: () => removeQuotationRow(index), - child: Container( - padding: const EdgeInsets.all(2), - // decoration: BoxDecoration( - // color: Colors.red.shade50, - // borderRadius: BorderRadius.circular(4), - // ), - child: Icon( - Icons.close, - size: 16, - color: Colors.red.shade700, + /// ❌ Delete Icon + Positioned( + top: 0, + right: 0, + child: GestureDetector( + onTap: () => removeQuotationRow(index), + child: Container( + padding: const EdgeInsets.all(2), + // decoration: BoxDecoration( + // color: Colors.red.shade50, + // borderRadius: BorderRadius.circular(4), + // ), + child: Icon( + Icons.close, + size: 16, + color: Colors.red.shade700, + ), ), ), ), - ), - ], - ), - ); - }, - ), - ], - - // ✅ END OF TABLE CODE - SizedBox(height: 20), - - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - GestureDetector( - onTap: () { - handleDone(); + ], + ), + ); }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 5, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4.0), - color: const Color(0xFF2E7D6E), + ), + ], + + // ✅ END OF TABLE CODE + SizedBox(height: 20), + + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF2E7D6E), + padding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 12, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), ), + onPressed: handleDone, child: Text( - 'Save', + 'Save All Quotes', style: GoogleFonts.poppins( color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w400, + fontSize: 13, + fontWeight: FontWeight.w500, ), ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), ), @@ -864,48 +1011,105 @@ class CreateProposal_QuickFormState dividerThickness: 0.3, columnSpacing: 10, columns: [ - DataColumn(label: Text("Agent Name", style: _tableHeaderStyle)), - DataColumn(label: Text("Reg No", style: _tableHeaderStyle)), + DataColumn(label: Text("Partner", style: _tableHeaderStyle)), + DataColumn( + label: Text("Vehicle Number", style: _tableHeaderStyle), + ), DataColumn(label: Text("Insurer", style: _tableHeaderStyle)), + DataColumn(label: Text("Plan Type", style: _tableHeaderStyle)), DataColumn(label: Text("Premium", style: _tableHeaderStyle)), DataColumn(label: Text("Action", style: _tableHeaderStyle)), ], + rows: filteredCreatedProposalData.expand((item) { + List quotationList = item["quotation_data"] ?? []; - rows: filteredCreatedProposalData.map((item) { - return DataRow( - cells: [ - DataCell( - Text(item["agent_name"] ?? "-", style: _tableDataStyle), + if (quotationList.isEmpty) { + // If no quotation, show single empty row + return [ + DataRow( + cells: [ + DataCell( + Text( + item["agent_name"] ?? "-", + style: _tableDataStyle, + ), + ), + DataCell( + Text(item["reg_no"] ?? "-", style: _tableDataStyle), + ), + DataCell(Text("-", style: _tableDataStyle)), + DataCell(Text("-", style: _tableDataStyle)), + DataCell(Text("-", style: _tableDataStyle)), + DataCell( + ElevatedButton( + onPressed: () { + print('handleProceed - Accepted'); + // Navigator.pop(context); + Navigator.of(context).pop(); + + context.go('/enquiryForStaff'); + // handleProceed('Accepted'); + }, + child: Text( + 'PROCEED', + style: GoogleFonts.poppins( + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], ), - DataCell( - Text(item["reg_no"] ?? "-", style: _tableDataStyle), - ), - DataCell( - Text( - item["insurer_short_name"] ?? "-", - style: _tableDataStyle, + ]; + } + + // Multiple quotations — return multiple DataRow + return quotationList.map((quote) { + return DataRow( + cells: [ + DataCell( + Text(item["agent_name"] ?? "-", style: _tableDataStyle), ), - ), - DataCell( - Text( - item["premium_amount"]?.toString() ?? "-", - style: _tableDataStyle, + DataCell( + Text(item["reg_no"] ?? "-", style: _tableDataStyle), ), - ), - DataCell( - TextButton( - onPressed: () {}, - child: Text( - 'PROCEED', - style: GoogleFonts.poppins( - fontSize: 10, - fontWeight: FontWeight.w500, + DataCell( + Text( + quote["insurer_short_name"] ?? "-", + style: _tableDataStyle, + ), + ), + DataCell( + Text( + quote["insurance_plan_type"] ?? "-", + style: _tableDataStyle, + ), + ), + DataCell( + Text( + "${quote["premium_amount"]}", + style: _tableDataStyle, + ), + ), + DataCell( + ElevatedButton( + onPressed: () { + print('handleProceed - Accepted'); + handleProceed('Accepted', quote['id']); + }, + child: Text( + 'PROCEED', + style: GoogleFonts.poppins( + fontSize: 10, + fontWeight: FontWeight.w500, + ), ), ), ), - ), - ], - ); + ], + ); + }).toList(); }).toList(), ), ), @@ -1139,7 +1343,8 @@ class CreateProposal_QuickFormState highlightColor: Color(0xFF50A398), padVertical: 10, isdense: true, - + errFieldHgt: 0.0, + errFieldFont: 0.0, inputFormatters: [ UpperCaseTextFormatter(), // 👈 custom formatter for uppercase FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9- ]')), @@ -1183,12 +1388,12 @@ class CreateProposal_QuickFormState itemAsString: (val) => val['short_name'].toString(), // what to show compareFn: (item, selectedItem) => item['id'] == selectedItem['id'], // ✅ compare by id - validator: (val) { - if (val == null) { - return "Required"; // ✅ error message - } - return null; - }, + // validator: (val) { + // if (val == null) { + // return "Required"; // ✅ error message + // } + // return null; + // }, suffixProps: DropdownSuffixProps( // make sure the dropdown button is visible dropdownButtonProps: DropdownButtonProps( @@ -1330,8 +1535,8 @@ class CreateProposal_QuickFormState inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), ], - validator: (value) => - Validators.doubleNumber(value, "PremiumAmount"), + // validator: (value) => + // Validators.doubleNumber(value, "PremiumAmount"), // validator: (value) => Validators.number(value, "PremiumAmount "), txtwidth: ResponsiveLayout.isMobile(context) ? null @@ -1360,138 +1565,172 @@ class CreateProposal_QuickFormState ? null : MediaQuery.of(context).size.width * 0.12, height: 30, - child: DropdownSearch>( - key: dropDownKey, - selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, - // items: (filter, infiniteScrollProps) { - // return filteredInsuranceData; - // }, - items: (filter, infiniteScrollProps) async { - if (filter.isEmpty) { - return filteredInsuranceData; - } - return filteredInsuranceData.where((item) { - return item['name'].toString().toLowerCase().contains( - filter.toLowerCase(), + child: FocusableActionDetector( + focusNode: partnerFocusNode, + autofocus: false, + onShowFocusHighlight: (hasFocus) { + setState(() { + focusedBorder: + OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: Color(0xFF50A398), + width: 2, + ), ); - }).toList(); - }, - itemAsString: (val) => val['insurance_plan_type'].toString(), - compareFn: (item, selectedItem) => - item['id'] == selectedItem['id'], // ✅ compare by id - validator: (val) { - if (val == null) { - return "Required"; // ✅ error message - } - return null; + }); // redraw to show highlight border }, + child: DropdownSearch>( + key: dropDownKey, + // focusNode: partnerFocusNode, + selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, + // items: (filter, infiniteScrollProps) { + // return filteredInsuranceData; + // }, + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredInsuranceData; + } + return filteredInsuranceData.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, - decoratorProps: DropDownDecoratorProps( - decoration: - AppInputDecorations.dropdownDecoration( - label: "Select Staff Member", - ).copyWith( - errorStyle: GoogleFonts.poppins(fontSize: 0, height: 0.0), - filled: true, - fillColor: - Colors.white, // 👈 makes the dropdown input white - isDense: true, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(5), - borderSide: const BorderSide( - color: Color(0xFFE2E8F0), - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(5), - borderSide: const BorderSide( - color: Color(0xFFE2E8F0), - width: 0.5, - ), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 8, - vertical: 6, - ), - ), - ), - popupProps: PopupProps.menu( - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - menuProps: MenuProps( - backgroundColor: - Colors.white, // 👈 sets dropdown background to white - ), - showSearchBox: true, - searchFieldProps: TextFieldProps( - autofocus: true, - decoration: InputDecoration( - contentPadding: EdgeInsets.all(1), - filled: true, - fillColor: Colors.white, - hintText: "Search Plan Type ...", - hintStyle: GoogleFonts.inter( - fontSize: 12, - color: Colors.black, - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.white, - ), // 👈 Normal border - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.white, - width: 1.5, - ), // 👈 Focused border + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), ), ), + itemAsString: (val) => val['insurance_plan_type'].toString(), + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + // validator: (val) { + // if (val == null) { + // return "Required"; // ✅ error message + // } + // return null; + // }, + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Staff Member", + ).copyWith( + errorStyle: GoogleFonts.poppins(fontSize: 0, height: 0.0), + filled: true, + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Plan Type ...", + hintStyle: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - // color: isSelected ? Colors.blue.withOpacity(0.1) : null, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 3, - ), - child: Text( - item['insurance_plan_type'].toString(), - style: GoogleFonts.inter(fontSize: 12, color: Colors.black), - ), - ); + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Text( + item['insurance_plan_type'].toString(), + style: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + ), + ); + }, + // searchFieldProps: TextFieldProps( + // decoration: InputDecoration( + // filled: true, + // fillColor: Colors.white, + // hintText: "Search Plan Type...", + // enabledBorder: OutlineInputBorder( + // borderSide: BorderSide( + // color: Colors.white, + // ), // 👈 Normal border + // ), + // focusedBorder: OutlineInputBorder( + // borderSide: BorderSide( + // color: Colors.white, + // width: 1.5, + // ), // 👈 Focused border + // ), + // ), + // ), + // constraints: BoxConstraints(), + ), + + onChanged: (val) { + if (val != null) { + print("Selected ClaimsType : ${val['insurance_plan_type']}"); + print("Id: ${val['id']}"); + selectedInsPlanType = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } }, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // filled: true, - // fillColor: Colors.white, - // hintText: "Search Plan Type...", - // enabledBorder: OutlineInputBorder( - // borderSide: BorderSide( - // color: Colors.white, - // ), // 👈 Normal border - // ), - // focusedBorder: OutlineInputBorder( - // borderSide: BorderSide( - // color: Colors.white, - // width: 1.5, - // ), // 👈 Focused border - // ), - // ), - // ), - // constraints: BoxConstraints(), ), - - onChanged: (val) { - if (val != null) { - print("Selected ClaimsType : ${val['insurance_plan_type']}"); - print("Id: ${val['id']}"); - selectedInsPlanType = val['id']; - // controllers['agentId']?.text = val['agent_code']; - // agentId = agent['id']; - } - }, ), ), ], diff --git a/lib/presentation/screens/staff/Enquiry/enquiry_inline_dec1.dart b/lib/presentation/screens/staff/Enquiry/enquiry_inline_dec1.dart new file mode 100644 index 0000000..2a6673e --- /dev/null +++ b/lib/presentation/screens/staff/Enquiry/enquiry_inline_dec1.dart @@ -0,0 +1,4696 @@ +import 'dart:async'; +import 'dart:ui'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/services.dart'; +import 'package:http/http.dart' as http; +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart'; +import 'package:nhance_partner/presentation/screens/staff/Enquiry/quotationPopUpAccptReject.dart'; +import 'package:nhance_partner/presentation/screens/staff/Enquiry/raise_enq_form.dart'; +import 'package:nhance_partner/presentation/screens/staff/Enquiry/staff_policy.dart'; +import 'package:nhance_partner/presentation/screens/staff/Enquiry/tabs/tab.dart'; +import 'package:nhance_partner/presentation/themes/indicators/customizd_multi_file_upload.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../../../core/config/env.dart'; +import '../../../../core/routing/routes.dart'; + +import '../../../../core/services/api_service.dart'; +import 'package:universal_html/html.dart' as html; + +import '../../../../data/services/auth_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../../data/utils/toastNotification.dart'; +import '../../../../data/utils/validators.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../providers/quotation_staff_proivder.dart'; +import '../../../providers/userRoleProvider.dart'; +import '../../../themes/indicators/customizd_file_upload.dart'; +import '../../../themes/indicators/export_btn.dart'; +import '../../../themes/indicators/input_field_decoration.dart'; +import '../../../themes/indicators/search_field_theme.dart'; +import '../../../themes/indicators/side_Drawer_Panel.dart'; +import '../../../themes/indicators/text_field_theme.dart'; +import '../../../themes/indicators/text_field_theme_inline_editor.dart' + hide UpperCaseTextFormatter; +import '../../../widgets/custom_Stdate_EnDate_Filter.dart'; +import '../assignStaff.dart'; +import 'multi_file_list.dart'; + +class EnquiryListStaffInline extends ConsumerStatefulWidget { + const EnquiryListStaffInline({super.key}); + @override + ConsumerState createState() => EnquiryStaffState(); +} + +class EnquiryStaffState extends ConsumerState { + int currentPage = 1; + int itemsPerPage = 10; + late ApiService apiService; + dynamic userId; + dynamic idPrimary; + dynamic managerId; + dynamic dashboardKey; + dynamic SelectedStatus; + dynamic SelectedStaffId; + String? selectedFileNames; + PlatformFile? docUploadedFile; + dynamic handlerId; + String? _token; + final _formKey = GlobalKey(); + Map fieldErrors = {}; + + bool _showEditDrawer = false; + + final raiseEnqKey = GlobalKey(); + + // List> dataVal = []; + List> getStaffData = []; + List> originalData = []; + List> filteredData = []; + bool isLoading = false; + dynamic roleId; + bool _showFilterRow = false; + + Map rowExpanded = {}; + Map controllers = {}; + List tabHeader = [ + 'startDate', + 'endDate', + 'name', + 'email', + 'mobile', + 'code', + 'address', + 'regNo', + 'remarks', + ]; + + Map isEditingRow = {}; + Map> rowControllers = {}; + + //---------------------- Enquiry TAB Initializations Starts -------------------------------- // + + List> getVehicleTypeData = []; + List> filteredVechicleData = []; + + List> getAgentListData = []; + List> filteredAgentData = []; + + List> getInsurersData = []; + List> filteredInsurersData = []; + + List> getPaymentModeData = []; + List> filteredPaymentModeData = []; + + List> getInsuranceTypeData = []; + List> filteredInsuranceData = []; + + String? selectedVehicleType; + String? selectedInsurer; + String? selectedInsPlanType; + String? selectedAgent; + PlatformFile? docUploadedRCFile; + PlatformFile? docUploadedIDProof; + PlatformFile? docUploadedPrevPolicy; + String? selectedPaymentMode; + + String? selectedRCFile; + String? selectedIdProof; + String? selectedPrevPolicy; + + String? selectedRCFileName; + + String? rcFileUrlFromApi; + String? idProofFileUrlFromApi; + String? prevPolicyFileUrlFromApi; + + String? selectedId; + + Map dataDetails() { + final data = { + "agent_id": + ((roleId == 'handler') || + (roleId == 'manager') || + (roleId == 'staff')) + ? selectedAgent + : userId, + "name": controllers["name"]?.text, + "mobile": controllers["mobile"]?.text, + "email": controllers["email"]?.text, + "reg_no": controllers["regNo"]?.text, + "vehicle_type_id": selectedVehicleType, + // "is_data_created_by_handler": roleId == 'handler' ? '1' : '0', + // "is_data_created_by_manager": roleId == 'manager' ? '1' : '0', + "is_data_created_by_staff": roleId != null ? '1' : '0', + // "insurer_id": selectedInsurer, + // "rc_file_name": "rc_doc.pdf", + // "id_proof_file_name": "id_proof.pdf", + // "previous_policy_file_name": "previous_policy.pdf", + "remarks": controllers["remarks"]?.text, + "assigned_to": selectedStaff, + "insurer_id": selectedInsurer, + "broker_id": selectedBroker, + "manager_id": managerId, + "created_by": userId, + }; + + return data; + } + + final GlobalKey>> dropDownKey = + GlobalKey>>(); + final GlobalKey>> + dropDownKeyInsurer = GlobalKey>>(); + final GlobalKey>> dropDownKeyAgent = + GlobalKey>>(); + + final GlobalKey>> + dropDownSelectPaymentModeKey = + GlobalKey>>(); + //---------------------- Assign Staff starts -------------------------------- // + + final GlobalKey>> + dropDownKeyInsurerEnqAsgn = + GlobalKey>>(); + + final GlobalKey>> dropDownKeyBroker = + GlobalKey>>(); + final GlobalKey>> + dropDownSelectStaffKey = + GlobalKey>>(); + + List> getStaffDetailsDataEnqAsgn = []; + List> filteredStaffDataEnqAsgn = []; + + String? selectedStaff; + String? selectedRegNum; + String? selectedStaffName; + + List> getBrokerData = []; + List> filteredBrokerData = []; + String? selectedBroker; + + final ScrollController _horizontalScrollController = ScrollController(); + late Timer timer; + + bool isActionable = false; + + //---------------------- Assign Staff Ends -------------------------------- // + //---------------------- Enquiry TAB Initializations Ends -------------------------------- // + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + timer = Timer.periodic(Duration(seconds: 30), (Timer t) => callRefresh()); + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + _initializeToken(); + + Future.microtask(() async { + // final id = ref.read(managerIdProvider); + roleId = ref.read(userRoleProvider); + userId = ref.read(userIdProvider); + managerId = ref.read(managerIdProvider); + + final prefs = await SharedPreferences.getInstance(); + dashboardKey = prefs.getString('dashboardKeyProvider'); + final dashboardStatus = prefs.getString('dashboardStatusProvider'); + final dashboardStaffId = prefs.getString('dashboardStaffIdProvider'); + + print('handlerIdENQ - $handlerId'); + print("C72 => r : $roleId | uId: $userId !mID : $managerId "); + + print('dashboardKey - $dashboardKey'); + print('dashboardStatus - $dashboardStatus'); + print('dashboardStaffId - $dashboardStaffId'); + + if (managerId != null && + dashboardKey != null && + dashboardStatus != null && + dashboardStaffId != null) { + print("DASHBOARD STATus-$dashboardStatus -- $dashboardStaffId -"); + SelectedStatus = dashboardStatus; + SelectedStaffId = dashboardStaffId; + getStaffList( + managerId, + roleId, + SelectedStatus: dashboardStatus, + SelectedStaffId: dashboardStaffId, + ); + } else { + print('ELSE'); + getStaffList(managerId, roleId); + } + if (managerId != null) { + print('managerId - $managerId'); + getAgentList(managerId); + } + + final userID = ref.watch(userIdProvider); + + print("managerId - $managerId"); + if (userID != null) { + print('hansles'); + getStaffDetailsForEnquiryAssignment(userID); + } + }); + + getVehicleType(); + getInsurers(); + getInsuranceType(); + getBroker(); + getPaymentMode(); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + void callRefresh() { + print('Call Refresh'); + if (!isActionable) { + print('Call Refresh isActionable'); + refrshfilterDateRange(); + } + } + + void refresh() { + final id = ref.read(managerIdProvider); + final roleId = ref.read(userRoleProvider); + final userId = ref.read(userIdProvider); + + print("C82 => r : $roleId | mId: $id | uId: $userId "); + if (managerId != null) { + getStaffList(managerId, roleId); + } + } + + void filterDateRange() { + // ✅ Call your API + getStaffList( + managerId, + roleId, + SelectedStatus: SelectedStatus ?? '', + SelectedStaffId: SelectedStaffId ?? '', + ); + } + + @override + void dispose() { + _horizontalScrollController.dispose(); + // ... dispose other controllers ... + super.dispose(); + } + + Future refrshfilterDateRange() async { + print('refrshfilterDateRange'); + // setState(() async { + final prefs = await SharedPreferences.getInstance(); + + // ✅ Clear any old data + await prefs.remove('dashboardKeyProvider'); + await prefs.remove('dashboardStatusProvider'); + await prefs.remove('dashboardStaffIdProvider'); + SelectedStatus = ''; + SelectedStaffId = null; + controllers['startDate']!.clear(); + controllers['endDate']!.clear(); + + controllers['startDate']?.text = ''; + controllers['endDate']?.text = ''; + // Reset the FormField validation + _formKey.currentState?.reset(); + // }); + + final int parsedManagerId = int.tryParse(managerId.toString()) ?? 0; + print('refrshfilterDateRange 1'); + getStaffList( + // managerId, + parsedManagerId, + roleId, + SelectedStatus: SelectedStatus ?? '', + SelectedStaffId: SelectedStaffId ?? '', + ); + print('refrshfilterDateRange 2'); + } + + Future getInsurers() async { + print('Insurers called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('Insurers'); + + if (response['status'] == 200) { + print('getInsurers - ${response['data']}'); + setState(() { + getInsurersData = List>.from(response['data']); + print('API Data - $getInsurersData'); + + filteredInsurersData = List.from(getInsurersData); + print('originalData - $filteredInsurersData'); + }); + } else { + getInsurersData = []; + filteredInsurersData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getInsuranceType() async { + print('getClaimList called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('InsuranceType'); + + if (response['status'] == 200) { + print('getInsuranceTypeData - ${response['data']}'); + setState(() { + getInsuranceTypeData = List>.from( + response['data'], + ); + print('API Data - $getInsuranceTypeData'); + + filteredInsuranceData = List.from(getInsuranceTypeData); + print('originalData - $filteredInsuranceData'); + }); + } else { + getInsuranceTypeData = []; + filteredInsuranceData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + 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(() { + getBrokerData = List>.from(response['data']); + print('API Data - $getBrokerData'); + + filteredBrokerData = List.from(getBrokerData); + print('originalData - $filteredBrokerData'); + }); + } else { + getBrokerData = []; + filteredBrokerData = []; + } + } 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; + }); + } + } + + Future getStaffDetailsForEnquiryAssignment(int id) async { + print('getStaffDetailsForEnquiryAssignment called By handler'); + setState(() { + isLoading = true; + }); + + try { + // final response = await apiService.fetchStaffUserList(id, role); + final response = await apiService.fetchStaffListForEnquiryAssignDropDown( + id, + roleId, + ); + + if (response['status'] == 'success') { + print('getStaffDetailsForEnquiryAssignment - ${response['data']}'); + setState(() { + getStaffDetailsDataEnqAsgn = List>.from( + response['data'], + ); + print('API Data - $getStaffDetailsDataEnqAsgn'); + + filteredStaffDataEnqAsgn = List.from(getStaffDetailsDataEnqAsgn); + print('originalData - $filteredStaffDataEnqAsgn'); + }); + } else { + getStaffDetailsDataEnqAsgn = []; + filteredStaffDataEnqAsgn = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getStaffList( + int managerId, + role, { + String fromDate = '', + String toDate = '', + String SelectedStatus = '', + String SelectedStaffId = '', + }) async { + print('A72 => Fns called => $managerId | $role'); + setState(() { + isLoading = true; + }); + + dynamic fromDt; + dynamic toDt; + + final fromDateVal = controllers['startDate']?.text ?? ''; + final toDateVal = controllers['endDate']?.text ?? ''; + final dateFormat = DateFormat('dd-MM-yyyy'); + + if (dashboardKey != 'fromDashboard' && + fromDateVal == '' && + toDateVal == '') { + print("ENQ LIST PAGE"); + + final today = DateTime.now(); + fromDt = dateFormat.format(today.subtract(Duration(days: 15))); + toDt = dateFormat.format(today); + + print('Enq FROM TO - $fromDt - $toDt'); + } else { + fromDt = fromDateVal; + toDt = toDateVal; + } + + try { + final response = await apiService.fetchEnquiryList( + managerId, + userId, + role, + fromDate: fromDt, + toDate: toDt, + selectedStatus: SelectedStatus != null ? SelectedStatus : '', + selectedStaffId: SelectedStaffId ?? '', + ); + + if (response['status'] == 'success') { + final data = 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) { + getStaffData = List>.from(data); + } else if (data is Map) { + getStaffData = [Map.from(data)]; + } else { + getStaffData = []; + } + originalData = getStaffData; + filteredData = List.from(originalData); + }); + } else { + getStaffData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + List get _paginatedData { + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + if (sortedData.isEmpty) return []; + + // Ensure currentPage is valid + final maxPage = (sortedData.length / itemsPerPage).ceil(); + final safePage = currentPage.clamp(1, maxPage); + + final startIndex = (safePage - 1) * itemsPerPage; + final endIndex = (startIndex + itemsPerPage).clamp(0, sortedData.length); + + return sortedData.sublist(startIndex, endIndex); + } + + void filterData(String query) { + print("FilterDAta - $query"); + setState(() { + filteredData = getStaffData.where((item) { + // final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive"; + + return (item['agent_name'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['reg_no'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['insurer_name'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['assigned_to_name'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['insured_name'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['premium_amount'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['payment_mode'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (_formatDate(item['created_on']) ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (_formatDate(item['updated_on']) ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['policy_number'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['status'] ?? '-').toLowerCase().contains(query.toLowerCase()); + }).toList(); + }); + } + + final TextEditingController _searchStaffController = TextEditingController(); + + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat( + 'dd-MM-yyyy HH:mm', + ).format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } + + Future handleStaff( + BuildContext context, + dynamic data, + id, + regNum, + ) async { + showDialog( + context: context, + builder: (ctx) => AssignStaffDialog( + enquiryPrimaryId: id, + regNum: regNum, + userId: userId, + onSubmit: (value) { + debugPrint("New assignY: $value"); + refresh(); + }, + ), + ); + } + + Future handleProposalAccept(BuildContext context, String id) async { + final result = showDialog( + context: context, + barrierDismissible: true, // allows tapping outside to close + builder: (ctx) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(26), + ), + insetPadding: const EdgeInsets.all(24), + child: Container( + width: 500, + height: 300, + color: Colors.white, + child: QuotationPopUpTab(id: id, onRefresh: refrshfilterDateRange), + ), + ); + }, + ); + + print("Dialog result: $result"); + (); + } + + void handleEdit(Map item) { + print("handleEdit"); + + final id = int.tryParse(item['id'].toString()) ?? 0; + idPrimary = item['id']; + + print("handleEdit - $idPrimary"); + setState(() { + selectedId = idPrimary; + isEditingRow[id] = true; + }); + for (final field in tabHeader) { + // Only set if controller exists + if (controllers.containsKey(field)) { + controllers[field]!.text = item[field] != null + ? item[field].toString() + : ''; // fallback to empty string + } + } + + //dropdowns or IDs + selectedVehicleType = item['vehicle_type_id']; + selectedAgent = item['agent_id']; + managerId = item['manager_id']; + controllers["regNo"]?.text = item['reg_no']; + controllers["remarks"]?.text = item['remarks']; + + selectedInsurer = item['insurer_id']; + selectedStaff = item['assigned_to']; + setState(() {}); + } + + Future handlePaymentMode(id, quotId) async { + Map data = { + "quotation_id": quotId, + "payment_mode_id": id, + "updated_by": userId, + }; + + final path = 'quotation/updateQuoteData'; + + final res = await apiService.createUserData(data, path); + + print("handlePaymentMode - $res"); + + if (res['status'] == 'success') { + print("handlePaymentModesuccess"); + refrshfilterDateRange(); + } + } + + Future handleInsurancePlanTypeMode(id, quotId) async { + Map data = { + "quotation_id": quotId, + "insurance_plan_type_id": id, + "updated_by": userId, + }; + + final path = 'quotation/updateQuoteData'; + + final res = await apiService.createUserData(data, path); + print("handleINSMode - $res"); + if (res['status'] == 'success') { + print("handleINSsuccess"); + refrshfilterDateRange(); + } + } + + void handleSave(dynamic id) { + print('SAVE -- $id'); + // final ids = int.tryParse(id.toString()) ?? 0; + + idPrimary = id; + handleEnqTabSave(); + } + + void handleCancel(int id) { + print('handleCancel id - $id'); + + final bool isNewRow = + int.tryParse(id.toString()) != null && + int.parse(id.toString()) > 1000000000000; + + print('isNewRow - $isNewRow'); + + setState(() { + if (isNewRow) { + // Check if this is a new unsaved row + final row = getStaffData.firstWhere( + (item) => item['id'].toString() == id.toString(), + orElse: () => {}, + ); + + // If policy_number is empty, it's a new row - remove it + if (row.isNotEmpty + // (row['policy_number'] == null || + // row['policy_number'] == '' || + // row['policy_number'] == '-') + ) { + getStaffData.removeWhere( + (item) => item['id'].toString() == id.toString(), + ); + originalData.removeWhere( + (item) => item['id'].toString() == id.toString(), + ); + filteredData.removeWhere( + (item) => item['id'].toString() == id.toString(), + ); + rowControllers.remove(id); + } + } + + // Turn off editing mode + isEditingRow.remove(id); + + // // Clear idPrimary if it matches + // if (idPrimary.toString() == id.toString()) { + // idPrimary = null; + // } + }); + } + + //-------------------------------Assign Logics staff start ---------------------------// + + Widget buildSelectStaffMem(ctx) { + Map? selectedVehicle; + try { + selectedVehicle = filteredStaffDataEnqAsgn.firstWhere( + (item) => item['id'].toString() == selectedStaff, + ); + } catch (e) { + selectedVehicle = null; // ✅ fallback + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Assigned To', style: _subLabelTimeStyle), + SizedBox(height: 5), + SizedBox( + height: 30, + width: MediaQuery.of(context).size.width * 0.08, + child: DropdownSearch>( + key: dropDownSelectStaffKey, + // selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, + selectedItem: selectedVehicle, + + // items: (filter, infiniteScrollProps) { + // return filteredStaffDataEnqAsgn; + // }, + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredStaffDataEnqAsgn; + } + return filteredStaffDataEnqAsgn.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, + + itemAsString: (val) => val['name'].toString(), + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Staff Member", + ).copyWith( + filled: true, + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0XFF6366F1), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0XFF6366F1), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null ? selectedItem['name'].toString() : "", + style: GoogleFonts.poppins( + fontSize: 11, + color: Color(0XFF6366F1), + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + autofocus: true, + style: GoogleFonts.inter(fontSize: 11, color: Colors.black), + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Staff ...", + hintStyle: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + // constraints: BoxConstraints(), + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Text( + item['name'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + ), + + onChanged: (val) { + if (val != null) { + print("Selected Staff : ${val['name']}"); + print("Id: ${val['id']}"); + selectedStaffName = val['name']; + selectedStaff = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget buildInsurer(BuildContext context, {fromHeader = true}) { + Map? selectedInsurerd = filteredInsurersData.firstWhere( + (item) => item['id'].toString() == selectedInsurer, + orElse: () => {}, + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Insurer', style: _subLabelTimeStyle), + SizedBox(height: 5), + Container( + height: 30, + width: fromHeader + ? MediaQuery.of(context).size.width * 0.1 + : MediaQuery.of(context).size.width * 0.08, + child: DropdownSearch>( + key: dropDownKeyInsurerEnqAsgn, + selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null, + // items: (filter, infiniteScrollProps) { + // return filteredInsurersData; + // }, + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredInsurersData; + } + return filteredInsurersData.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, + + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null ? selectedItem['name'].toString() : "", + style: GoogleFonts.poppins( + fontSize: 11, + color: Color(0XFF6366F1), + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Insurer", + ).copyWith( + filled: true, + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0XFF6366F1), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0XFF6366F1), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 200), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + style: GoogleFonts.inter(fontSize: 11, color: Colors.black), + + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Insurer...", + hintStyle: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Text( + item['name'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + // constraints: BoxConstraints(), + ), + + onChanged: (val) { + if (val != null) { + print("Selected Insurer : ${val['name']}"); + print("Id: ${val['id']}"); + selectedInsurer = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget buildBroker(BuildContext context) { + Map? selectedBrokers = filteredBrokerData.firstWhere( + (item) => item['id'].toString() == selectedBroker, + orElse: () => {}, + ); + return SizedBox( + height: 30, + width: MediaQuery.of(context).size.width * 0.07, + child: DropdownSearch>( + key: dropDownKeyBroker, + selectedItem: selectedBrokers.isNotEmpty ? selectedBrokers : null, + items: (filter, infiniteScrollProps) { + return filteredBrokerData; + }, + + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null ? selectedItem['name'].toString() : "", + style: GoogleFonts.poppins(fontSize: 11, color: Colors.black), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Broker", + ).copyWith( + filled: true, + fillColor: Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: Colors.black, width: 0.1), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: Colors.black, width: 0.1), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + style: GoogleFonts.inter(fontSize: 11, color: Colors.black), + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Broker...", + hintStyle: GoogleFonts.inter(fontSize: 12, color: Colors.black), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + child: Text( + item['name'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + // constraints: BoxConstraints(), + ), + + onChanged: (val) { + if (val != null) { + print("Selected Broker : ${val['name']}"); + print("Id: ${val['id']}"); + selectedBroker = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ); + } + + // -------------------------------Assign Logics staff end---------------------------// + + //---------------------- Enquiry TAB Logins Starts -------------------------------- // + + Map dataEnquiryTabDetails() { + final data = { + "agent_id": ((roleId == 'handler') || (roleId == 'manager')) + ? selectedAgent + : userId, + "name": controllers["name"]?.text, + "mobile": controllers["mobile"]?.text, + "email": controllers["email"]?.text, + "reg_no": controllers["regNo"]?.text, + "vehicle_type_id": selectedVehicleType, + "is_data_created_by_handler": roleId == 'handler' ? '1' : '0', + "is_data_created_by_manager": roleId == 'manager' ? '1' : '0', + // "insurer_id": selectedInsurer, + // "rc_file_name": "rc_doc.pdf", + // "id_proof_file_name": "id_proof.pdf", + // "previous_policy_file_name": "previous_policy.pdf", + "remarks": controllers["remarks"]?.text, + "manager_id": managerId, + "created_by": userId, + }; + + return data; + } + + Future getVehicleType() async { + print('getClaimList called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('vehicleType'); + + if (response['status'] == 200) { + print('getVehicleTypeData - ${response['data']}'); + setState(() { + getVehicleTypeData = List>.from( + response['data'], + ); + print('API Data - $getVehicleTypeData'); + + filteredVechicleData = List.from(getVehicleTypeData); + print('originalData - $filteredVechicleData'); + }); + } else { + getVehicleTypeData = []; + filteredVechicleData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getAgentList(id) async { + print('getAgentListData called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchAgentNameDropDown(id); + print('getAgentListData called response'); + print('get Agent- ${response['data']}'); + if (response['status'] == 'success') { + print('get Agent- ${response['data']}'); + setState(() { + getAgentListData = List>.from(response['data']); + print('API Data - $getAgentListData'); + + filteredAgentData = List.from(getAgentListData); + print('originalAgentData - $filteredAgentData'); + }); + } else { + getAgentListData = []; + filteredAgentData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Widget buildAgentName(BuildContext context, {fromHeader = true}) { + Map? selectedAgntName = filteredAgentData.firstWhere( + (item) => item['id'].toString() == selectedAgent, + orElse: () => {}, + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Partner', style: _subLabelTimeStyle), + SizedBox(height: 5), + SizedBox( + width: MediaQuery.of(context).size.width * 0.08, + // width: fromHeader + // ? MediaQuery.of(context).size.width * 0.11 + // : MediaQuery.of(context).size.width * 0.08, + height: 30, + child: DropdownSearch>( + key: dropDownKeyAgent, + selectedItem: selectedAgntName.isNotEmpty ? selectedAgntName : null, + // items: (filter, infiniteScrollProps) { + // return filteredAgentData; + // }, + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredAgentData; + } + return filteredAgentData.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, + + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['name'].toString() + : "", // ✅ FIXED + style: GoogleFonts.poppins( + fontSize: 11, + color: Color(0XFF6366F1), + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Partner Name", + ).copyWith( + filled: true, + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0XFF6366F1), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0XFF6366F1), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + + searchFieldProps: TextFieldProps( + autofocus: true, + style: GoogleFonts.inter(fontSize: 11, color: Colors.black), + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Partner Name", + hintStyle: GoogleFonts.inter( + fontSize: 10, + color: Colors.black, + ), + + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + // constraints: BoxConstraints(), + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + item['name'].toString(), + style: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + ), + Text( + item['agent_code'].toString(), + style: GoogleFonts.inter( + fontSize: 11, + color: Colors.grey, + ), + ), + ], + ), + ); + }, + ), + + onChanged: (val) { + if (val != null) { + print("Selected Partner : ${val['name']}"); + print("Id: ${val['id']}"); + selectedAgent = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget buildVehicleNumber(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Vehicle Number', style: _subLabelTimeStyle), + SizedBox(height: 5), + SizedBox( + width: MediaQuery.of(context).size.width * 0.08, + child: ThemedFormInlineField( + controller: controllers['regNo']!, + hintText: 'Vehicle Number', + borderColor: Color(0XFF6366F1), + textColr: Color(0XFF6366F1), + isdense: true, + inputFormatters: [ + UpperCaseTextFormatter(), // 👈 custom formatter for uppercase + FilteringTextInputFormatter.allow(RegExp(r'[A-Za-z0-9- ]')), + ], + validator: (value) => Validators.requiredVechileNum(value, "regNo"), + widthNone: true, + ), + ), + ], + ); + } + + Widget buildInsuredName(BuildContext context, {fromHeader = true}) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Insured', style: _subLabelTimeStyle), + SizedBox(height: 5), + SizedBox( + width: fromHeader + ? MediaQuery.of(context).size.width * 0.1 + : MediaQuery.of(context).size.width * 0.08, + child: ThemedFormInlineField( + controller: controllers['name']!, + hintText: 'Insured Name', + textColr: Color(0XFF6366F1), + // errorText: fieldErrors['name'], + borderColor: Color(0XFF6366F1), + isdense: true, + validator: (value) => Validators.requiredField(value, "name"), + widthNone: true, + ), + ), + ], + ); + } + + Widget buildVehicleType(BuildContext context) { + // Find the matching map from your list + + Map? selectedVehicle = filteredVechicleData.firstWhere( + (item) => item['id'].toString() == selectedVehicleType, + orElse: () => {}, + ); + + return SizedBox( + width: MediaQuery.of(context).size.width * 0.07, + height: 30, + child: DropdownSearch>( + key: dropDownKey, + selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, + items: (filter, infiniteScrollProps) { + return filteredVechicleData; + }, + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + + itemAsString: (val) => val['vehicle_type'].toString(), + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['vehicle_type'].toString() + : "", // ✅ FIXED + style: GoogleFonts.poppins(fontSize: 11, color: Color(0XFF6366F1)), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Vehicle Type", + ).copyWith( + filled: true, + fillColor: Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: Colors.black, width: 0.1), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: Colors.black, width: 0.1), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 200), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + style: GoogleFonts.inter(fontSize: 11, color: Colors.black), + padding: const EdgeInsets.all(1.0), + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Vehicle Type...", + hintStyle: GoogleFonts.inter(fontSize: 10, color: Colors.black), + labelStyle: GoogleFonts.inter(fontSize: 10, color: Colors.black), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.white), // 👈 Normal border + ), + isDense: true, // reduces height + // contentPadding: const EdgeInsets.symmetric( + // horizontal: 8, + // vertical: 8, // reduce this value for smaller height + // ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + // constraints: BoxConstraints(), + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + child: Text( + item['vehicle_type'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + ), + + onChanged: (val) { + if (val != null) { + print("Selected vehicle_type : ${val['vehicle_type']}"); + print("Id: ${val['id']}"); + selectedVehicleType = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ); + } + + Widget buildEmail(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Email', style: _subLabelTimeStyle), + SizedBox(height: 5), + SizedBox( + width: MediaQuery.of(context).size.width * 0.1, + child: ThemedFormInlineField( + controller: controllers['email']!, + borderColor: Color(0XFF6366F1), + textColr: Color(0XFF6366F1), + hintText: 'Email', + isdense: true, + validator: (value) => Validators.nonReqemail(value, "email"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_@.]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.16, + ), + ), + ], + ); + } + + Widget buildPhNumber(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Mobile', style: _subLabelTimeStyle), + SizedBox(height: 5), + SizedBox( + width: MediaQuery.of(context).size.width * 0.1, + child: ThemedFormInlineField( + controller: controllers['mobile']!, + borderColor: Color(0XFF6366F1), + textColr: Color(0XFF6366F1), + hintText: 'Mobile', + isdense: true, + validator: (value) => Validators.nonReqphone(value, "phone"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[ 0-9]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ), + ], + ); + } + + Widget buildRemarks(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Remarks', style: _subLabelTimeStyle), + SizedBox(height: 5), + ThemedFormField( + // maxLength: 500, + enableBorderWidth: 0.5, + hintText: 'Remarks', + controller: controllers['remarks']!, + borderColor: Color(0XFF6366F1), + textColr: Color(0XFF6366F1), + verticalPad: 10, + horizonalPad: 10, + isdense: true, + // keyboardType: TextInputType.multiline, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.1, + ), + ], + ); + } + + Widget buildPaymentMode(context) { + Map? selectedVehicle = filteredPaymentModeData.firstWhere( + (item) => item['id'].toString() == selectedPaymentMode, + orElse: () => {}, + ); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Payment Mode", style: _textStyle), + // SizedBox(height: 10), + SizedBox( + // color: Colors.red, + // color: Colors.yellow, + width: 200, + // height: 30, + // width: ResponsiveLayout.isMobile(context) + // ? null + // : MediaQuery.of(context).size.width * 0.18, + // height: 35, + child: DropdownSearch>( + key: dropDownSelectPaymentModeKey, + selectedItem: selectedVehicle.isNotEmpty ? selectedVehicle : null, + // items: (filter, infiniteScrollProps) { + // return filteredInsuranceData; + // }, + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredPaymentModeData; + } + return filteredPaymentModeData.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, + itemAsString: (val) => val['value'].toString(), + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Payment Mode", + ).copyWith( + filled: true, + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + popupProps: PopupProps.dialog( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 400, maxWidth: 300), + // constraints: BoxConstraints(maxHeight: 250), + dialogProps: DialogProps(backgroundColor: Colors.white), + // menuProps: MenuProps( + // backgroundColor: + // Colors.white, // 👈 sets dropdown background to white + // ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Payment Mode ...", + hintStyle: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Text( + item['value'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + ), + + onChanged: (val) { + if (val != null) { + print("Selected value : ${val['value']}"); + print("Id: ${val['id']}"); + selectedPaymentMode = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget buildResponsiveUploadField({ + required String label, + required String? hintText, + required double? width, + required void Function(String fileName, dynamic file) onFileSelected, + bool showDownload = false, + VoidCallback? onRemove, + VoidCallback? onDownload, + }) { + final isMobile = ResponsiveLayout.isMobile(context); + + final uploadWidget = ThemedMultiFileUploadField( + hintText: hintText ?? "Upload Document", + txtwidth: width, + // txtwidth: MediaQuery.of(context).size.width * 0.08, + padVertical: 6, + padHorizontal: 8, + + backgroundColor: Colors.white, + // backgroundColor: Color(0xffD9EBE8), + txtName: label, + isTxtBtnCase: true, + onFileSelected: onFileSelected, + ); + + // final uploadWidget = ThemedUploadField( + // hintText: hintText ?? "Upload Document", + // txtwidth: width, + // // txtwidth: MediaQuery.of(context).size.width * 0.08, + // padVertical: 6, + // padHorizontal: 8, + // + // backgroundColor: Colors.white, + // // backgroundColor: Color(0xffD9EBE8), + // txtName: label, + // isTxtBtnCase: true, + // onFileSelected: onFileSelected, + // ); + + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [uploadWidget], + ), + ], + ); + } + + Widget buildUploadRCDocument(BuildContext context) { + return SizedBox( + // width: MediaQuery.of(context).size.width * 0.08, + child: buildResponsiveUploadField( + label: "RC", + width: 60, + hintText: selectedRCFile, + onFileSelected: (fileName, file) { + setState(() { + docUploadedRCFile = file; + selectedRCFileName = fileName; + }); + ToastHelper.showSuccessToast(context, 'File Uploaded Successfully'); + }, + showDownload: docUploadedRCFile != null || rcFileUrlFromApi != null, + onRemove: () { + setState(() { + docUploadedRCFile = null; + rcFileUrlFromApi = null; + selectedRCFileName = null; + }); + }, + onDownload: () => apiService.downloadFile( + // apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId', + apiUrl: + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc', + + apiId: selectedId.toString(), + + localFile: docUploadedRCFile, + fileName: 'RC', + ), + ), + ); + } + + Widget buildUploadIDDocument(BuildContext context) { + return SizedBox( + // width: MediaQuery.of(context).size.width * 0.08, + child: buildResponsiveUploadField( + label: "ID Proof", + width: 80, + hintText: selectedIdProof, + onFileSelected: (fileName, file) { + setState(() { + docUploadedIDProof = file; + // selectedFileNames = fileName; + }); + + ToastHelper.showSuccessToast(context, 'File Uploaded Successfully'); + }, + showDownload: + docUploadedIDProof != null || idProofFileUrlFromApi != null, + onRemove: () { + setState(() { + docUploadedIDProof = null; + idProofFileUrlFromApi = null; + // selectedFileNames = null; + }); + }, + onDownload: () => apiService.downloadFile( + // apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId', + apiUrl: + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof', + + apiId: selectedId.toString(), + localFile: docUploadedIDProof, + fileName: 'Id_Proof', + ), + ), + ); + } + + Widget buildUploadPolicyDocument(BuildContext context) { + return SizedBox( + // width: MediaQuery.of(context).size.width * 0.08, + child: buildResponsiveUploadField( + width: 100, + label: "PrevPolicy", + hintText: selectedPrevPolicy, + onFileSelected: (fileName, file) { + setState(() { + docUploadedPrevPolicy = file; + // selectedFileNames = fileName; + }); + ToastHelper.showSuccessToast(context, 'File Uploaded Successfully'); + }, + showDownload: + docUploadedPrevPolicy != null || prevPolicyFileUrlFromApi != null, + onRemove: () { + setState(() { + docUploadedPrevPolicy = null; + prevPolicyFileUrlFromApi = null; + // selectedFileNames = null; + }); + }, + onDownload: () => apiService.downloadFile( + // apiUrl: 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId', + apiUrl: + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy', + + apiId: selectedId.toString(), + localFile: docUploadedPrevPolicy, + fileName: 'Previous_Policy', + ), + ), + ); + } + + Widget buildDocRC(BuildContext context, selectedEnquiryId) { + return SizedBox( + width: MediaQuery.of(context).size.width * 0.16, + child: InkWell( + onTap: () { + print("Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc'; + print("Uploadpath $path"); + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Tooltip( + message: 'Download RC', + child: Text( + "RC", + style: GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ), + ); + } + + Widget buildDocIdProof(BuildContext context, selectedEnquiryId) { + return InkWell( + onTap: () { + print("Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof'; + print("Uploadpath $path"); + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Tooltip( + message: 'Download ID Proof', + child: Text( + "ID Proof", + style: GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ); + } + + Widget buildDocPrevPolicy(BuildContext context, selectedEnquiryId) { + return InkWell( + onTap: () { + print("QD597 Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy'; + + print("Uploadpath $path"); + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Tooltip( + message: 'Download Previous Policy', + child: Text( + "Prev Policy", + style: GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ); + } + + // Update validation method to set errors + bool _validateRequiredFields() { + setState(() { + fieldErrors.clear(); // Clear previous errors + + // Validate Partner/Agent + if (selectedAgent == null || selectedAgent == '') { + fieldErrors['agent'] = 'Partner is required'; + } + + // Validate Insured Name + if (controllers['name']?.text.trim().isEmpty ?? true) { + fieldErrors['name'] = 'Insured Name is required'; + } + + // Validate Vehicle Number + if (controllers['regNo']?.text.trim().isEmpty ?? true) { + fieldErrors['regNo'] = 'Vehicle Number is required'; + } + + // Validate Vehicle Type + if (selectedVehicleType == null || selectedVehicleType == '') { + fieldErrors['vehicleType'] = 'Vehicle Type is required'; + } + + // Validate email format if provided + final email = controllers['email']?.text.trim() ?? ''; + if (email.isNotEmpty) { + final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + if (!emailRegex.hasMatch(email)) { + fieldErrors['email'] = 'Invalid email format'; + } + } + + // Validate mobile number if provided + final mobile = controllers['mobile']?.text.trim() ?? ''; + if (mobile.isNotEmpty) { + final cleanMobile = mobile.replaceAll(' ', ''); + if (cleanMobile.length < 10) { + fieldErrors['mobile'] = 'Must be at least 10 digits'; + } + } + }); + + return true; + + return fieldErrors.isEmpty; + } + + Future handleEnqTabSave() async { + if (!_validateRequiredFields()) return; + + // setState(() { + // isSaving = true; // start saving + // }); + + final dataSet = dataDetails(); + + try { + await createUserData(dataSet); // API call + + // ToastHelper.showInfoToast(context, "Enquiry saved successfully"); + } catch (e) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: const Text('Error'), + content: Text(e.toString()), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('OK'), + ), + ], + ), + ); + } finally { + // setState(() => isSaving = false); // re-enable button after save + } + } + + Future attachFiles(http.MultipartRequest request) async { + Future addFileOrKeepName( + PlatformFile? file, + String? apiFileName, + String fieldName, + ) async { + if (file != null) { + // User uploaded a new file → send as multipart + if (file.bytes != null) { + request.files.add( + http.MultipartFile.fromBytes( + fieldName, + file.bytes!, + filename: file.name, + ), + ); + } else if (file.path != null) { + request.files.add( + await http.MultipartFile.fromPath( + fieldName, + file.path!, + filename: file.name, + ), + ); + } + print("📎 Attached new file → $fieldName"); + } else if (apiFileName != null && apiFileName.isNotEmpty) { + // No new upload → tell backend to keep old file + request.fields[fieldName] = apiFileName; + print("🔗 Kept old file → $fieldName = $apiFileName"); + } else { + // Nothing at all + request.fields[fieldName] = ""; + } + } + + await addFileOrKeepName( + docUploadedRCFile, + rcFileUrlFromApi, + 'rc_file_name', + ); + await addFileOrKeepName( + docUploadedIDProof, + idProofFileUrlFromApi, + 'id_proof_file_name', + ); + await addFileOrKeepName( + docUploadedPrevPolicy, + prevPolicyFileUrlFromApi, + 'previous_policy_file_name', + ); + } + + List _buildPopupDownload(BuildContext context, selectId) { + bool isMobile = ResponsiveLayout.isMobile(context); + return [ + // editing + // ? + Container( + // color: Colors.red.shade50, + padding: EdgeInsets.only(top: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + + children: [ + buildUploadRCDocument(context), + SizedBox(width: 3), + buildUploadIDDocument(context), + SizedBox(width: 3), + buildUploadPolicyDocument(context), + ], + ), + ), + ]; + } + + Widget _buildSubRow(context, selectId, id) { + return Wrap( + spacing: 12, + runSpacing: 12, + children: [ + buildSelectStaffMem(context), + buildAgentName(context, fromHeader: false), + buildInsurer(context), + buildInsuredName(context), + buildVehicleNumber(context), + + buildEmail(context), + buildPhNumber(context), + buildRemarks(context), + + // Padding( + // padding: const EdgeInsets.only(top: 8.0), + // child: Builder( + // builder: (buttonContext) => Material( + // // color: Color(0xFFFFFCF2), + // color: Color(0xFFF8F9FF), + // child: InkWell( + // hoverColor: Color(0xFFF8F9FF), + // // hoverColor: const Color(0xFFFFFCF2), + // // hoverColor: const Color(0xFFEAF6F4), + // onTap: () async { + // // ✅ Get overlay and button position RELATIVE to InkWell + // final RenderBox button = + // buttonContext.findRenderObject() as RenderBox; + // final RenderBox overlay = + // Overlay.of(buttonContext).context.findRenderObject() + // as RenderBox; + // + // final Offset position = button.localToGlobal( + // Offset.zero, + // ancestor: overlay, + // ); + // + // await showMenu( + // context: buttonContext, + // position: RelativeRect.fromLTRB( + // position.dx, + // position.dy + button.size.height, + // overlay.size.width, + // 0, + // ), + // items: [ + // PopupMenuItem( + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: _buildPopupDownload( + // buttonContext, + // selectId, + // ), + // ), + // ), + // ], + // // color: Colors.white, + // // color: Color(0xFFFFFCF2), + // color: Color(0xFFF8F9FF), + // ); + // }, + // child: Tooltip( + // message: 'Click To Upload Documents', + // + // waitDuration: const Duration(milliseconds: 500), + // showDuration: const Duration(seconds: 2), + // child: Container( + // padding: EdgeInsets.all(8.0), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(50), + // ), + // child: Icon( + // Icons.upload_file, + // color: Color(0XFF6366F1), + // // editing ? Icons.upload_file : Icons.download_for_offline, + // // color: editing ? Colors.b lue : Colors.green, + // size: 20, + // ), + // ), + // ), + // ), + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: IconButton( + tooltip: 'Save', + padding: EdgeInsets.zero, + constraints: const BoxConstraints(minWidth: 24, minHeight: 24), + icon: const Icon( + Icons.check, + color: Colors.green, + size: 28, // smaller icon + ), + splashRadius: 14, // ripple radius + onPressed: () => { + setState(() { + rowExpanded[id] = !(rowExpanded[id] ?? false); + }), + handleSave(selectId), + }, + ), + ), + ], + ); + } + + List _buildPopupDownload_BTN( + BuildContext context, + dynamic data, + id, + regNum, + ) { + bool isMobile = ResponsiveLayout.isMobile(context); + return [ + Row( + children: [ + buildDocRC_BTN(context, isMobile, id), + Spacer(), + // SizedBox(width: 3), + buildDocIdProof_BTN(context, isMobile, id), + Spacer(), + buildDocPrevPolicy_BTN(context, isMobile, id), + ], + ), + ]; + } + + Widget buildDocRC_BTN( + BuildContext context, + bool isMobile, + selectedEnquiryId, + ) { + return GestureDetector( + onTap: () { + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc'; + + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "RC", + style: GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 2), + // isMobile ? const Spacer() : const SizedBox(width: 15), + const Icon( + Icons.file_download_outlined, + size: 16, + color: Colors.white, + ), + ], + ), + ), + ); + } + + Widget buildDocIdProof_BTN( + BuildContext context, + bool isMobile, + selectedEnquiryId, + ) { + return GestureDetector( + onTap: () { + print("Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "ID Proof", + style: GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 2), + // const SizedBox(width: 15), + Icon(Icons.file_download_outlined, size: 16, color: Colors.white), + ], + ), + ), + ); + } + + Widget buildDocPrevPolicy_BTN( + BuildContext context, + bool isMobile, + selectedEnquiryId, + ) { + return GestureDetector( + onTap: () { + print("QD597 Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 6), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Previous Policy", + style: GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 2), + // isMobile ? const Spacer() : const SizedBox(width: 15), + Icon(Icons.file_download_outlined, size: 16, color: Colors.white), + ], + ), + ), + ); + } + + Future createUserData(Map userData) async { + final bool isNewRow = + idPrimary != null && + int.tryParse(idPrimary.toString()) != null && + int.parse(idPrimary.toString()) > 1000000000000; + + final bool isUpdating = + idPrimary != null && idPrimary != 'null' && !isNewRow; + + print('isNewRow: $isNewRow, isUpdating: $isUpdating'); + + // final bool isUpdating = idPrimary != 'null'; + final id = idPrimary; + print('UPDId- $id'); + + // final bool isUpdating = false; + final uri = Uri.parse( + isUpdating + ? '${Env.apiUrl}enquiry/updateEnquiry' + : '${Env.apiUrl}enquiry/createEnquiry', + ); + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + // Use MultipartRequest (POST only) + final request = http.MultipartRequest('POST', uri); + request.headers['Authorization'] = 'Bearer $_token'; + request.headers['app-signature'] = Env.App_Signature; + + // If updating, spoof the method Laravel-style + if (isUpdating) { + request.fields['id'] = id!; + request.fields['updated_by'] = userId!.toString(); + } else { + request.fields['created_by'] = userId!.toString(); + } + + print("USerDAta - $userData"); + + // userData.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + await attachFiles(request); + userData.forEach((key, value) { + if (key != 'rc_file_name' && key != 'id_proof_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + } else { + print('Something Missing..'); + } + }); + + // attach files + + // request.fields['agent_id'] = selectedId.toString(); + + print(" Sending request with fields: ${request.fields}"); + + try { + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + print("Response status: ${response.statusCode}"); + print("Response body: ${response.body}"); + + if (response.statusCode == 200 || response.statusCode == 201) { + // dispose(); + print("✅ Enquiry submitted successfully!"); + ToastHelper.showSuccessToast(context, 'Saved Enquiry'); + print("Response: ${response.body}"); + // Clear the temporary ID + idPrimary = null; + refrshfilterDateRange(); + // getStaffList(managerId, roleId); + // setState(() => isSaving = false); + } else if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + } else { + print("❌ Submission failed. Status: ${response.statusCode}"); + print("Body: ${response.body}"); + + // setState(() => isSaving = false); + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("Enquiry Creation Failed"), + content: Text( + "There was a problem in creating enquiry. Please try again.", + ), + actions: [ + TextButton( + child: Text("OK"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } + } + + Future uploadPolicyPDF({ + required Map data, + required PlatformFile? file, + }) async { + if (_token == null) throw Exception("Token missing. Please login."); + + final uri = Uri.parse('${Env.apiUrl}policy/uploadPolicyFile'); + final request = http.MultipartRequest('POST', uri); + + request.headers['Authorization'] = 'Bearer $_token'; + request.headers['app-signature'] = Env.App_Signature; + + print("🔥 Upload Request Data: $data"); + + // 1️⃣ Add text fields (except file) + data.forEach((key, value) { + if (value != null && key != 'policy_pdf_file_name') { + request.fields[key] = value.toString(); + print("➡️ Field Added: $key = ${request.fields[key]}"); + } + }); + + // 2️⃣ Attach file + if (file != null) { + if (file.bytes != null) { + request.files.add( + http.MultipartFile.fromBytes( + 'policy_pdf_file_name', + file.bytes!, + filename: file.name, + ), + ); + } else if (file.path != null) { + request.files.add( + await http.MultipartFile.fromPath( + 'policy_pdf_file_name', + file.path!, + filename: file.name, + ), + ); + } + print("📎 File attached: ${file.name}"); + } else { + print("⚠️ No file selected!"); + } + + // 3️⃣ Submit request + try { + final response = await http.Response.fromStream(await request.send()); + + print("📥 Response Code: ${response.statusCode}"); + print("📥 Response Body: ${response.body}"); + + if (response.statusCode == 200 || response.statusCode == 201) { + ToastHelper.showSuccessToast(context, "Policy PDF Uploaded!"); + refrshfilterDateRange(); + return; + } + + if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + return; + } + + ToastHelper.showErrorToast(context, "Upload failed!"); + } catch (e) { + print("❌ Error uploading file: $e"); + } + } + + //---------------------- Enquiry TAB Logins End -------------------------------- // + @override + Widget build(BuildContext context) { + return MainLayout( + title: "Enquiries", + body: Container( + // color: Colors.yellow.shade50, + // color: Color(0xFFFCFCFC), + // color: Colors.white, + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(12), + // boxShadow: [ + // BoxShadow( + // color: Colors.black.withOpacity(0.08), + // blurRadius: 8, + // spreadRadius: 1, + // offset: const Offset(0, 2), // soft drop shadow + // ), + // ], + // ), + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.1, + // padding: EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + // height: MediaQuery.of(context).size.height*0. + child: RaiseEnqForm( + key: raiseEnqKey, + onSubmit: (dataSet) async { + print('Check checking dataSet $dataSet'); + try { + await createUserData(dataSet); // <-- API call here + print("Enquiry saved successfully"); + // RESET FORM + raiseEnqKey.currentState?.resetFormFields(); + } catch (e) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: const Text('Error'), + content: Text(e.toString()), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('OK'), + ), + ], + ), + ); + } + }, + ), + ), + + // SizedBox(height: 5), + ResponsiveLayout.isMobile(context) + ? Container( + height: MediaQuery.of(context).size.height * 0.69, + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(2), + child: _buildContent(context), + ), + ), + ) + : + // Expanded( + // child: + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height * 0.69, + // padding: EdgeInsets.symmetric( + // horizontal: 8.0, + // vertical: 2.0, + // ), + child: _buildContent(context), + ), + + // ), + // Container( + // // height: 20, + // width: MediaQuery.of(context).size.width, + // // color: Colors.green.shade50, + // child: PaginationControls( + // currentPage: currentPage, + // itemsPerPage: itemsPerPage, + // // totalItems: dataVal.length, + // totalItems: filteredData.length, + // // activeColor: layoutColor, // your theme color + // onPageChanged: (page) { + // setState(() { + // currentPage = page; + // }); + // }, + // onItemsPerPageChanged: (items) { + // setState(() { + // itemsPerPage = items; + // currentPage = 1; + // }); + // }, + // ), + // ), + ], + ), + ), + ); + } + + Future buildStatusActions(BuildContext context, status, id) async { + print("Actionsstatus - $status -$id"); + dynamic val; + if (status == 'Awaiting Proposal' || status == 'Proposal Created') { + val = ''; + } else { + val = 'Policy'; + } + + final result = await showDialog( + context: context, + barrierDismissible: + false, // optional - prevents closing by tapping outside + builder: (context) => TabEnquiryStaffList(showKey: val), + ); + + // ✅ Code here runs *after* the dialog is closed + print("Dialog closed"); + print("Dialog result: $result"); + refrshfilterDateRange(); + } + + Future buildPolicyCreatedStatusActions( + BuildContext context, + status, + id, + ) async { + print("Actionsstatus - $status -$id"); + dynamic val; + if (status == 'Awaiting Proposal' || status == 'Proposal Created') { + val = ''; + } else { + val = 'Policy'; + } + + final result = await showDialog( + context: context, + barrierDismissible: + false, // optional - prevents closing by tapping outside + builder: (context) => PolicyStaffEnqList(), + ); + + // ✅ Code here runs *after* the dialog is closed + print("Dialog closed"); + print("Dialog result: $result"); + if (result) { + setState(() { + isActionable = false; + }); + } + refrshfilterDateRange(); + } + + Widget _buildContent(BuildContext context) { + final isDesktop = !ResponsiveLayout.isMobile(context); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 10), + Container( + // height: 40, + // color: Color(0xffF1F5F9), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (_showFilterRow) ...[ + DateFilterRow( + key: ValueKey(SelectedStatus ?? ''), + role: roleId, + id: userId, + selectedStatusVal: SelectedStatus, + onFilterStaff: (val) { + print('Selected Filterd STAFF Id - $val'); + SelectedStaffId = val; + }, + selectedStaffId: SelectedStaffId, + startController: controllers['startDate']!, + endController: controllers['endDate']!, + onStatusChanged: (val) { + SelectedStatus = val; // update parent + }, + formKey: _formKey, + isMobile: ResponsiveLayout.isMobile(context), + onFilter: () { + // call your filter logic + filterDateRange(); + }, + onRefresh: () { + // call your refresh logic + refrshfilterDateRange(); + }, + ), + ], + IconButton( + icon: Icon( + _showFilterRow + ? Icons.close_fullscreen + : Icons.filter_alt_outlined, + ), + iconSize: 18, + color: const Color(0xFF94A3B8), + tooltip: _showFilterRow ? 'Hide Filters' : 'Show Filters', + onPressed: () { + setState(() { + _showFilterRow = !_showFilterRow; + }); + }, + ), + ThemedSearchField( + hintText: 'Search', + backgroundColor: Color(0xFFFFFFFF), + txtHeight: 30, + // backgroundColor: Colors.white, + onChanged: filterData, + + controller: _searchStaffController, + txtwidth: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.width * 0.7 + : MediaQuery.of(context).size.width * 0.13, + ), + SizedBox(width: 10), + ExportBtn( + sheetName: "Enquiry", + fileName: "Enquiry_list", + data: filteredData, + txt: !ResponsiveLayout.isMobile(context) ? true : false, + displayHeaders: [ + "Received Date & Time", + "Partner", + "Assigned To", + "Insurer", + "Vehicle.No.", + "Insured Name", + "Assigned Date & Time", + "Premium", + "Payment Mode", + "Policy Number", + "Status", + ], + keys: [ + "created_on", + "agent_name", + "assigned_to_name", + "insurer_name", + "reg_no", + "insured_name", + "updated_on", + "premium_amount", + "payment_mode", + "policy_number", + "status", + ], + ), + ], + ), + ), + + SizedBox(height: 5), + + ResponsiveLayout.isMobile(context) + ? _buildDataTable(context) + : + // Expanded( + // child: + Container( + height: MediaQuery.of(context).size.height * 0.55, + decoration: BoxDecoration(color: Colors.white), + child: _buildDataTable(context), + ), + // ), + ], + ); + } + + // 1. Add group expansion state tracking + Map groupExpanded = { + // 'Awaiting Proposal': true, + // 'Proposal Created': true, + // 'Proposal Accepted': true, + // 'Proposal Rejected': true, + 'Awaiting Payment': true, + 'Policy Created': true, + }; + + Map statusGroupMap = { + // 'Awaiting Proposal': 'Awaiting Proposal', + // 'Proposal Created': 'Proposal Created', + // 'Proposal Accepted': 'Proposal Created', + // 'Proposal Rejected': 'Proposal Created', + 'Proposal Created': 'Awaiting Payment', + 'Proposal Accepted': 'Awaiting Payment', + 'Proposal Rejected': 'Awaiting Payment', + 'Policy Created': 'Policy Created', + }; + + // Add group enquiries by status + Map>> get _groupedEnquiries { + final grouped = >>{}; + + // Initialize all status groups + // grouped['Awaiting Proposal'] = []; + // grouped['Proposal Created'] = []; + // grouped['Proposal Accepted'] = []; + // grouped['Proposal Rejected'] = []; + // grouped['Policy Created'] = []; + grouped['Awaiting Payment'] = []; + + // Initialize only the groups you need + // grouped['Awaiting Proposal'] = []; + // grouped['Proposal Created'] = []; + grouped['Policy Created'] = []; + + // Group the filtered/paginated data by status + // for (var item in _paginatedData) { + // final status = item['status']?.toString() ?? 'Unknown'; + // if (grouped.containsKey(status)) { + // grouped[status]!.add(item); + // } + // } + + for (var item in filteredData) { + final status = item['status']?.toString() ?? 'Unknown'; + + // Map actual status to grouped status + final groupKey = statusGroupMap[status]; + + if (groupKey != null) { + grouped[groupKey]!.add(item); + } + } + + // for (var item in _paginatedData) { + // final status = item['status']?.toString() ?? 'Unknown'; + // + // // Map actual status to grouped status + // final groupKey = statusGroupMap[status]; + // + // if (groupKey != null) { + // grouped[groupKey]!.add(item); + // } + // } + + return grouped; + } + + Map _getStatusConfig(String status) { + switch (status) { + case 'Awaiting Proposal': + return {'icon': '🕐', 'color': Color(0xFFfff3cd)}; + case 'Proposal Created': + return {'icon': '📝', 'color': Color(0xFFd1ecf1)}; + // case 'Proposal Accepted': + // return {'icon': '✅', 'color': Color(0xFFd4edda)}; + // case 'Proposal Rejected': + // return {'icon': '❌', 'color': Color(0xFFf8d7da)}; + case 'Policy Created': + return {'icon': '📋', 'color': Color(0xFFcfe2ff)}; + default: + return {'icon': '📄', 'color': Color(0xFFe9ecef)}; + } + } + + final Map statusColors = { + 'Awaiting Proposal': const Color(0xFFEFF6FF), // Blue 50 + 'Proposal Created': const Color(0xFFF0F9FF), // Cyan 50 + 'Proposal Accepted': const Color(0xFFF0FDF4), // Green 50 + 'Proposal Rejected': const Color(0xFFFEF9C3), // Yellow 50 + 'Policy Created': const Color(0xFFF3F0FF), // Purple 50 (generated) + }; + + final Map statusBorderColors = { + 'Awaiting Proposal': const Color(0xFFDBEAFE), // Blue 100 + 'Proposal Created': const Color(0xFFBAE6FD), // Cyan 100 + 'Proposal Accepted': const Color(0xFFDCFCE7), // Green 100 + 'Proposal Rejected': const Color(0xFFFEF3C7), // Yellow 100 + 'Policy Created': const Color(0xFFF0E4FF), // Purple 200 + // 'Policy Created': const Color(0xFFE5CCFF), // Purple 200 + }; + + final Map statusTextColors = { + 'Awaiting Proposal': const Color(0xFF1D4ED8), // Blue 700 + 'Proposal Created': const Color(0xFF0369A1), // Cyan 700 + 'Proposal Accepted': const Color(0xFF15803D), // Green 700 + 'Proposal Rejected': const Color(0xFFB45309), // Amber 700 + 'Policy Created': const Color(0xFF6B21A8), // Purple 700 + }; + + // 4. Build group header widget + Widget _buildGroupHeader(String status, int count) { + final config = _getStatusConfig(status); + final isExpanded = groupExpanded[status] ?? true; + + return InkWell( + onTap: () { + setState(() { + groupExpanded[status] = !isExpanded; + }); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4), + child: Row( + children: [ + Icon( + isExpanded ? Icons.arrow_drop_down : Icons.arrow_right, + size: 22, + color: Color(0xFF5A6C7D), + ), + SizedBox(width: 8), + Text( + // '${config['icon']} $status', + '$status', + style: GoogleFonts.inter( + fontSize: 13, + color: Colors.black, + // color: Colors.orange, + fontWeight: FontWeight.w600, + ), + ), + // Spacer(), + SizedBox(width: 8), + Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2), + decoration: BoxDecoration( + color: Color(0xFFEFF6FF), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + '$count', + style: GoogleFonts.inter( + fontSize: 11, + color: Color(0xFF2563EB), + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildDataTable(context) { + final screenWidth = MediaQuery.of(context).size.width; + final isMobile = ResponsiveLayout.isMobile(context); + + // Calculate minimum width based on screen size + double minTableWidth = isMobile ? screenWidth * 1.5 : 1300; + return + // Expanded( + // child: + LayoutBuilder( + builder: (context, constraints) { + // double minWidth = constraints.maxWidth < 1300 + // ? 1300 + // : constraints.maxWidth; + double tableWidth = constraints.maxWidth > minTableWidth + ? constraints.maxWidth + : minTableWidth; + + final isDesktop = !ResponsiveLayout.isMobile(context); + + return ScrollConfiguration( + behavior: const MaterialScrollBehavior().copyWith( + dragDevices: {PointerDeviceKind.mouse, PointerDeviceKind.touch}, + ), + child: SingleChildScrollView( + controller: _horizontalScrollController, // 👈 Shared controller + scrollDirection: Axis.horizontal, + child: SizedBox( + // width: minWidth, + width: tableWidth, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Fixed Header + Container( + decoration: BoxDecoration( + // color: Colors.white, + color: Color(0xFFF1F5F9), + borderRadius: BorderRadius.circular(5), + // boxShadow: [ + // BoxShadow( + // color: Colors.black.withOpacity(0.08), + // blurRadius: 8, + // spreadRadius: 1, + // offset: const Offset(0, 2), + // ), + // ], + ), + child: _buildTableHeader(isDesktop), + ), + + // Scrollable Data Content + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + // border: Border.all(color: Colors.grey, width: 0.1), + // boxShadow: [ + // BoxShadow( + // color: Colors.black.withOpacity(0.08), + // blurRadius: 8, + // spreadRadius: 1, + // offset: const Offset(0, 2), + // ), + // ], + ), + child: _buildDataTableContent(), // 👈 New method + ), + ), + ], + ), + ), + ), + ); + }, + ); + // ); + } + + Widget _buildDataTableContent() { + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + final groupedData = _groupedEnquiries; + + return SingleChildScrollView( + scrollDirection: Axis.vertical, // 👈 Only vertical scroll here + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ...groupedData.entries.map((entry) { + final status = entry.key; + final items = entry.value; + final isExpanded = groupExpanded[status] ?? true; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // Group Header + if (status != 'Proposal Accepted' && + status != 'Proposal Rejected') ...[ + Container( + // width: double.infinity, + width: MediaQuery.of(context).size.width, + margin: EdgeInsets.fromLTRB(12, 4, 12, 4), + child: _buildGroupHeader(status, items.length), + ), + ], + // Group rows + if (isExpanded && items.isNotEmpty) + ...items.asMap().entries.map((itemEntry) { + final index = itemEntry.key; + final item = itemEntry.value; + final startIndex = (currentPage - 1) * itemsPerPage; + final sno = startIndex + index + 1; + final id = int.tryParse(item['id'].toString()) ?? 0; + final selectId = item['id'].toString() ?? '0'; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // Data row + Container( + width: MediaQuery.of( + context, + ).size.width, // margin: EdgeInsets.all(10.0), + margin: EdgeInsets.fromLTRB(12, 8, 12, 8), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Color(0xFFFFECF1F7)), + // border: Border( + // left: BorderSide(color: Color(0XFFE2E8F0)), + // right: BorderSide(color: Color(0XFFE2E8F0)), + // bottom: BorderSide(color: Color(0XFFE2E8F0)), + // top: BorderSide(color: Color(0XFFE2E8F0)), + // ), + borderRadius: BorderRadius.circular(8), + // boxShadow: [ + // BoxShadow( + // color: Color(0XFFE2E8F0), + // blurRadius: 3, + // spreadRadius: 0.2, + // offset: const Offset(0, 1), // soft drop shadow + // ), + // ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + DataTable( + border: TableBorder.all( + color: Colors.transparent, + width: 0, + ), + // border: TableBorder( + // top: BorderSide.none, + // left: BorderSide.none, + // right: BorderSide.none, + // bottom: BorderSide.none, + // horizontalInside: BorderSide.none, + // verticalInside: BorderSide.none, + // ), + headingRowHeight: 0, + dividerThickness: 0.1, + columnSpacing: 20.0, + dataRowMinHeight: 40, + columns: _buildDataColumns(), + rows: [_buildDataRow(item, sno)], + ), + + // Expanded content + if (rowExpanded[id] ?? false) + Container( + // width: double.infinity, + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + // borderRadius: const BorderRadius.only( + // topLeft: Radius.circular(25), + // topRight: Radius.circular(25), + // ), + border: Border.all( + color: Color(0xFFC7D2FE), + ), + + color: Color(0xFFF8F9FF), + ), + padding: const EdgeInsets.symmetric( + vertical: 14.0, + horizontal: 8.0, + ), + child: _buildSubRow(context, selectId, id), + ), + ], + ), + ), + ], + ); + }).toList(), + + if (isExpanded && items.isEmpty) + if (status != 'Proposal Accepted' && + status != 'Proposal Rejected') + Padding( + padding: EdgeInsets.all(5), + child: Center( + child: Text( + 'No enquiries found', + style: GoogleFonts.inter( + fontSize: 12, + color: Colors.grey, + fontStyle: FontStyle.italic, + ), + ), + ), + ), + ], + ); + }).toList(), + ], + ), + ); + } + + DataRow _buildDataRow(Map item, int sno) { + final id = int.tryParse(item['id'].toString()) ?? 0; + final selectId = item['id'].toString() ?? '0'; + + final bool isNewRow = + int.tryParse(id.toString()) != null && + int.parse(id.toString()) > 1000000000000; + + print('idPrimary - $idPrimary'); + print('isNewRow - $isNewRow'); + final editing = isEditingRow[id] ?? false; + final controllers = rowControllers[id]; + + String status = item['status'] ?? '-'; + + Color bgColor = statusColors[status] ?? Color(0xFFF9FAFB); + Color borderColor = statusBorderColors[status] ?? Color(0xFFE2E8F0); + + return DataRow( + cells: [ + DataCell( + SizedBox( + width: 70, + child: Row( + children: [ + // Text(item['created_on'], style: _dataBold), + Text( + formatDateTimeForTable(item['created_on'], newLine: true), + style: _dataBoldthm1, + ), + ], + ), + ), + ), + // Assigned To + DataCell( + SizedBox( + // flex: 1, + width: 110, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + item['assigned_to_name'] != null + ? _truncateText(item['assigned_to_name'], 15) + : '-', + style: _dataBold, + ), + Text(_formatDate(item['updated_on']), style: _dataBoldthm4), + ], + ), + ), + ), + + // Agent Name + DataCell( + SizedBox( + width: 100, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(item['agent_code'] ?? '-', style: _dataBold), + Text( + item['agent_name'] != null + ? _truncateText(item['agent_name'], 20) + : '-', + style: _tableDataTimeStyle, + ), + ], + ), + ), + ), + + // Insurer Name + DataCell( + SizedBox( + width: 60, + child: Text( + item['insurer_short_name'] ?? '-', + style: _dataBoldthm2, + ), + ), + ), + + DataCell( + SizedBox( + width: 90, + child: Tooltip( + message: item['insured_name'], + child: Text( + item['insured_name'] != null + ? _truncateText(item['insured_name'], 15) + : '-', + style: _dataBoldthm2, + ), + ), + ), + ), + // Vehicle No + DataCell( + SizedBox( + width: 95, + child: Builder( + builder: (buttonContext) => Material( + color: Colors.white, + // child: InkWell( + // // hoverColor: Color(0xFFEAF6F4), + // onTap: () async { + // // ✅ Get overlay and button position RELATIVE to InkWell + // final RenderBox button = + // buttonContext.findRenderObject() as RenderBox; + // final RenderBox overlay = + // Overlay.of(buttonContext).context.findRenderObject() + // as RenderBox; + // + // final Offset position = button.localToGlobal( + // Offset.zero, + // ancestor: overlay, + // ); + // + // await showMenu( + // context: buttonContext, + // position: RelativeRect.fromLTRB( + // position.dx, + // position.dy + button.size.height, + // overlay.size.width, + // // overlay.size.width - position.dx, + // 0, + // ), + // items: [ + // PopupMenuItem( + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: _buildPopupDownload_BTN( + // buttonContext, + // item, + // item['id'], + // item['reg_no'], + // ), + // ), + // ), + // ], + // color: Colors.white, + // ); + // }, + child: Tooltip( + message: + 'Click and Download Enquiry Files', // what appears on hover/long press + waitDuration: const Duration(milliseconds: 500), // optional + showDuration: const Duration(seconds: 2), // optional + child: Container( + padding: EdgeInsets.all(4.0), + margin: EdgeInsets.symmetric(vertical: 3, horizontal: 2), + decoration: BoxDecoration( + color: Color(0xFFF9FAFB), + border: Border.all(color: Color(0xFFE2E8F0)), + borderRadius: BorderRadius.circular(5), + ), + child: Text(item['reg_no'] ?? '-', style: _dataBoldthm3), + ), + ), + // child: Text(item['reg_no'] ?? '-', style: _dataBold), + // ), + ), + ), + ), + ), + + DataCell( + SizedBox( + width: 70.0, + child: Row( + children: [ + Tooltip( + richMessage: WidgetSpan( + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + // color: Colors.white, + color: Color(0xFFFFFCF2), + borderRadius: BorderRadius.circular(6), + // border: Border.all(color: Colors.blueGrey.shade100), + // border: Border.all(color: Colors.grey.shade400), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + + // mainAxisSize: MainAxisSize.min, + children: [ + _row("Email", item["email"]), + _row("Mobile", item["mobile"]), + _row("Remarks", item["remarks"]), + ], + ), + ), + ), + padding: EdgeInsets + .zero, // important (remove default tooltip padding) + verticalOffset: 12, // distance from icon + waitDuration: Duration(milliseconds: 500), + showDuration: Duration(seconds: 2), + decoration: BoxDecoration(), // remove default yellow box + child: Icon( + Icons.info_outline_rounded, + size: 15, + color: Colors.blue, + ), + ), + IconButton( + padding: EdgeInsets.zero, // remove outer padding + constraints: BoxConstraints( + // reduce clickable area + minWidth: 24, + minHeight: 24, + ), + icon: Icon( + rowExpanded[id] == true ? Icons.edit_off_sharp : Icons.edit, + color: Colors.blue, + size: 15, + ), + + tooltip: "Edit", + onPressed: () { + setState(() { + isActionable = false; + bool isOpen = rowExpanded[id] ?? false; + + rowExpanded.clear(); // close all + + if (!isOpen) { + isActionable = true; + rowExpanded[id] = + true; // open only if previously closed + } + // rowExpanded[id] = !(rowExpanded[id] ?? false); + }); + handleEdit(item); + }, + ), + Builder( + builder: (buttonContext) => Material( + color: Colors.white, + child: InkWell( + // hoverColor: Color(0xFFEAF6F4), + onTap: () async { + // ✅ Get overlay and button position RELATIVE to InkWell + final RenderBox button = + buttonContext.findRenderObject() as RenderBox; + final RenderBox overlay = + Overlay.of(buttonContext).context.findRenderObject() + as RenderBox; + + final Offset position = button.localToGlobal( + Offset.zero, + ancestor: overlay, + ); + + await showMenu( + context: buttonContext, + position: RelativeRect.fromLTRB( + position.dx, + position.dy + button.size.height, + overlay.size.width, + // overlay.size.width - position.dx, + 0, + ), + items: [ + PopupMenuItem( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [MultipleFileWidget(enqId: selectId)], + ), + ), + ], + color: Colors.white, + ); + }, + child: Tooltip( + message: + 'Click and Upload / Download Enquiry Files', // what appears on hover/long press + waitDuration: const Duration( + milliseconds: 500, + ), // optional + showDuration: const Duration(seconds: 2), // optional + child: Icon( + Icons.file_upload_outlined, + size: 15, + color: Colors.green, + ), + ), + ), + ), + ), + ], + ), + ), + ), + + // Assigned Date (formatted) + // DataCell( + // SizedBox( + // width: 80, + // child: Text( + // // item['updated_on'] ?? '-', + // formatDateTimeForTable(item['updated_on'], newLine: true), + // style: _dataBold, + // softWrap: true, + // maxLines: 3, + // ), + // ), + // ), + + // Premium + // DataCell( + // // (item['status'] == 'Proposal Created' || + // // item['status'] == 'Proposal Rejected') + // // ? SizedBox( + // // width: 80, + // // child: InkWell( + // // onTap: () { + // // // handle approval logic + // // + // // handleProposalAccept(context, item['id']); + // // }, + // // child: Text( + // // 'Click To\nApprove', + // // style: GoogleFonts.inter( + // // color: Colors.green, + // // fontSize: 11, + // // fontWeight: FontWeight.w700, + // // ), + // // ), + // // ), + // // ) + // // : + // SizedBox( + // width: 90, + // child: Text( + // item['premium_amount']?.toString() ?? '-', + // style: _dataBold, + // ), + // ), + // ), + + // // Payment Mode + // DataCell( + // // Material(child: buildPaymentMode(context)), + // SizedBox( + // // width: 80, + // // child: Text(item['payment_mode_value'] ?? '-', style: _dataBold), + // child: buildPaymentMode(context), + // ), + // ), + DataCell( + SizedBox( + height: 30, + width: 120, + child: (item['status'] == 'Awaiting Proposal') + ? Text('-') + : Builder( + builder: (cellContext) => + DropdownSearch>( + key: ValueKey(item['id']), + + selectedItem: () { + try { + return filteredPaymentModeData.firstWhere( + (mode) => + mode['id'].toString() == + item['payment_mode_id'].toString(), + orElse: () => {}, + ); + } catch (e) { + return null; + } + }(), + + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredPaymentModeData; + } + return filteredPaymentModeData.where((paymentMode) { + return paymentMode['value'] + .toString() + .toLowerCase() + .contains(filter.toLowerCase()); + }).toList(); + }, + + itemAsString: (val) => val['value'].toString(), + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: + EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 8, // smaller icon + color: Colors.black45, + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + + dropdownBuilder: (context, selectedItem) { + // Check if selectedItem is null or empty map + bool isEmpty = + selectedItem == null || + selectedItem.isEmpty || + selectedItem['value'] == null; + + return Container( + padding: EdgeInsets.zero, + // padding: EdgeInsets.symmetric(horizontal: 2), + alignment: Alignment.centerLeft, + child: Text( + isEmpty + ? "Select Payment Mode" + : selectedItem['value'].toString(), + style: GoogleFonts.poppins( + fontSize: 11, + color: isEmpty + ? Colors + .grey + .shade500 // Grey for hint + : Colors.black, // Blue for selected + // : Color(0XFF6366F1), // Blue for selected + fontWeight: isEmpty + ? FontWeight.w400 + : FontWeight.w400, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ); + }, + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + // label: "Select Payment Mode", + ).copyWith( + filled: true, + fillColor: Colors + .white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + //color: Color(0xFFFFFFFF), + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 1, + vertical: 6, + ), + ), + ), + // 🔥 Use PopupProps.menu - works better in tables + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 300, + minWidth: 200, + ), + menuProps: MenuProps( + backgroundColor: Colors.white, + elevation: 8, + borderRadius: BorderRadius.circular(8), + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(8), + filled: true, + fillColor: Color(0xFFF8FAFC), + hintText: "Search...", + hintStyle: GoogleFonts.inter( + fontSize: 11, + color: Colors.grey, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: Color(0xFFE2E8F0), + ), + ), + ), + ), + itemBuilder: + (context, item, isDisabled, isSelected) { + return Container( + color: isSelected + ? Colors.blue.withOpacity(0.1) + : Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, + ), + child: Text( + item['value'].toString(), + style: GoogleFonts.inter( + fontSize: 11, + color: Colors.black87, + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.normal, + ), + ), + ); + }, + ), + + onChanged: (val) { + dynamic id; + if (val != null) { + setState(() { + item['payment_mode_id'] = val['id'].toString(); + item['payment_mode'] = val['value'].toString(); + id = val['id'].toString(); + }); + } + handlePaymentMode(id, item['quotation_id']); + }, + ), + ), + ), + ), + DataCell( + SizedBox( + width: 120, + height: 30, + child: (item['status'] == 'Awaiting Proposal') + ? Text('-') + : Builder( + builder: (cellContext) => DropdownSearch>( + key: ValueKey(item['id']), + selectedItem: () { + try { + return filteredInsuranceData.firstWhere( + (mode) => + mode['insurance_plan_type'] + .toString() + .trim() + .toLowerCase() == + item['insurance_plan_type'] + .toString() + .trim() + .toLowerCase(), + orElse: () => {}, + ); + } catch (e) { + return null; + } + }(), + + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredInsuranceData; + } + return filteredInsuranceData.where((paymentMode) { + return paymentMode['insurance_plan_type'] + .toString() + .toLowerCase() + .contains(filter.toLowerCase()); + }).toList(); + }, + + itemAsString: (val) => + val['insurance_plan_type'].toString(), + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 8, // smaller icon + color: Colors.black45, + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + + dropdownBuilder: (context, selectedItem) { + // Check if selectedItem is null or empty map + bool isEmpty = + selectedItem == null || + selectedItem.isEmpty || + selectedItem['insurance_plan_type'] == null; + + return Container( + padding: EdgeInsets.zero, + // padding: EdgeInsets.symmetric(horizontal: 2), + alignment: Alignment.centerLeft, + child: Text( + isEmpty + ? "Select Insurer" + : selectedItem['insurance_plan_type'] + .toString(), + style: GoogleFonts.poppins( + fontSize: 11, + color: isEmpty + ? Colors + .grey + .shade500 // Grey for hint + : Colors.black, // Blue for selected + // : Color(0XFF6366F1), // Blue for selected + fontWeight: isEmpty + ? FontWeight.w400 + : FontWeight.w400, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ); + }, + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + // label: "Select Payment Mode", + ).copyWith( + filled: true, + fillColor: Colors + .white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + //color: Color(0xFFFFFFFF), + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 1, + vertical: 6, + ), + ), + ), + // 🔥 Use PopupProps.menu - works better in tables + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints( + maxHeight: 300, + minWidth: 200, + ), + menuProps: MenuProps( + backgroundColor: Colors.white, + elevation: 8, + borderRadius: BorderRadius.circular(8), + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(8), + filled: true, + fillColor: Color(0xFFF8FAFC), + hintText: "Search...", + hintStyle: GoogleFonts.inter( + fontSize: 11, + color: Colors.grey, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide(color: Color(0xFFE2E8F0)), + ), + ), + ), + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + color: isSelected + ? Colors.blue.withOpacity(0.1) + : Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 5, + vertical: 5, + ), + child: Text( + item['insurance_plan_type'].toString(), + style: GoogleFonts.inter( + fontSize: 11, + color: Colors.black87, + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.normal, + ), + ), + ); + }, + ), + + onChanged: (val) { + dynamic id; + if (val != null) { + setState(() { + // item['payment_mode_id'] = val['id'].toString(); + item['insurance_plan_type'] = + val['insurance_plan_type'].toString(); + id = val['id'].toString(); + }); + } + handleInsurancePlanTypeMode(id, item['quotation_id']); + }, + ), + ), + ), + ), + + // DataCell( + // buildPaymentMode(context), + // // Builder( + // // builder: (cellContext) => buildPaymentMode(cellContext), + // // // SizedBox(width: 200, child: buildPaymentMode(cellContext)), + // // ), + // ), + + // Policy Number + DataCell( + SizedBox( + height: 30, + width: 90, + child: (item['status'] == 'Awaiting Proposal') + ? Text('-') + : ThemedUploadField( + // hintText: item['policy_pdf_file_name'] ?? "Upload Document", + hintText: + selectedFileNames ?? + item['policy_pdf_file_name'] ?? + "Upload Document", + // txtheight: 30, + padHorizontal: 4, + padVertical: 5, + fontSZ: 11, + borderCirculr: 5, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.18, + borderColor: Color(0xFFE2E8F0), + + // highlightColor: Color(0xFF50A398), + // backgroundColor: Color(0xFFEDF6F5), + onFileSelected: (fileName, file) async { + print("Picked file: $fileName (${file.size} bytes)"); + + if (!fileName.toLowerCase().endsWith('.pdf')) { + ToastHelper.showErrorToast( + context, + 'Only PDF files are allowed.', + ); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Only PDF files are allowed.'), + backgroundColor: Colors.red, + ), + ); + return; // Stop here + } + + print("Picked file: $fileName (${file.size} bytes)"); + setState(() { + docUploadedFile = file; + }); + await uploadPolicyPDF( + file: docUploadedFile, + data: { + "quotation_id": item["quotation_id"], + "manager_id": managerId, + "created_by": userId, + "updated_by": userId, + // "id": item["id"], // ONLY while updating + }, + ); + // if (selectedBrokerName == 'Nhance') { + // handleUploadPolicy(); + // } + }, + ), + ), + ), + + DataCell( + SizedBox( + width: 120, + + child: Material( + color: Colors.white, + child: InkWell( + // hoverColor: Color(0xFFEAF6F4), + // onTap: null, + onTap: () async { + setState(() { + isActionable = true; + }); + buildPolicyCreatedStatusActions( + context, + item['status'], + item['id'], + ); + }, + child: Tooltip( + message: 'Click to View or Process Enquiry', // + waitDuration: const Duration(milliseconds: 500), // optional + showDuration: const Duration(seconds: 2), // optional + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.0), + margin: EdgeInsets.symmetric(vertical: 2), + decoration: BoxDecoration( + // color: Color(0xFFF9FAFB), + // border: Border.all(color: Color(0xFFE2E8F0)), + color: bgColor, + border: Border.all(color: borderColor), + borderRadius: BorderRadius.circular(5), + ), + + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + item['status'] ?? '-', + style: GoogleFonts.inter( + fontSize: 10, + color: Color(0XFF1e293b), + // color: statusTextColors[status] ?? Colors.black, + fontWeight: FontWeight.w500, + ), + // overflow: TextOverflow.clip, // + ), + ], + ), + ), + ), + // child: Text(item['status'] ?? '-', style: _dataBold), + ), + ), + ), + ), + // DataCell( + // SizedBox( + // width: 120, + // + // child: Material( + // color: Colors.white, + // child: InkWell( + // // hoverColor: Color(0xFFEAF6F4), + // onTap: () async { + // var status = item['status']; + // var enqId = item['id']; + // + // final prefs = await SharedPreferences.getInstance(); + // + // // ✅ Remove old value (if any) + // await prefs.remove('enqStaffDataId'); + // + // // ✅ Save the new id + // await prefs.setString('enqStaffDataId', enqId.toString()); + // ref.read(quotationStaffIdProvider.notifier).state = enqId; + // buildStatusActions(context, status, enqId); + // }, + // child: Tooltip( + // message: 'Click to View or Process Enquiry', // + // waitDuration: const Duration(milliseconds: 500), // optional + // showDuration: const Duration(seconds: 2), // optional + // child: Container( + // padding: EdgeInsets.symmetric(vertical: 2.0), + // margin: EdgeInsets.symmetric(vertical: 2), + // decoration: BoxDecoration( + // // color: Color(0xFFF9FAFB), + // // border: Border.all(color: Color(0xFFE2E8F0)), + // color: bgColor, + // border: Border.all(color: borderColor), + // borderRadius: BorderRadius.circular(5), + // ), + // + // child: Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text( + // item['status'] ?? '-', + // style: GoogleFonts.inter( + // fontSize: 10, + // color: Color(0XFF1e293b), + // // color: statusTextColors[status] ?? Colors.black, + // fontWeight: FontWeight.w500, + // ), + // // overflow: TextOverflow.clip, // + // ), + // ], + // ), + // ), + // ), + // // child: Text(item['status'] ?? '-', style: _dataBold), + // ), + // ), + // ), + // ), + ], + ); + } + + // Add this helper method to generate DataColumns + List _buildDataColumns() { + return [ + DataColumn(label: Text('Received Date', style: _headerStyle)), + DataColumn(label: Text('Assigned To *', style: _headerStyle)), + DataColumn(label: Text('Partner *', style: _headerStyle)), + + // const DataColumn(label: Text('Broker *', style: _headerStyle)), + DataColumn(label: Text('Insurer *', style: _headerStyle)), + DataColumn(label: Text('Insured Name *', style: _headerStyle)), + DataColumn(label: Text('Vehicle No *', style: _headerStyle)), + DataColumn(label: Text('Action', style: _headerStyle)), + // const DataColumn(label: Text('Assigned Date', style: _headerStyle)), + // DataColumn(label: Text('Premium', style: _headerStyle)), + DataColumn(label: Text('Payment Mode', style: _headerStyle)), + DataColumn(label: Text('Plan Type', style: _headerStyle)), + DataColumn(label: Text('Policy', style: _headerStyle)), + DataColumn(label: Text('Status', style: _headerStyle)), + ]; + } + + // 6. Build table header + Widget _buildTableHeader(bool isDesktop) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: [ + _buildHeaderCell('Received Date', 110), + _buildHeaderCell('Assigned To *', 130), + _buildHeaderCell('Partner *', 100), + + // _buildHeaderCell('Broker *', 100), + _buildHeaderCell('Insurer *', 90), + _buildHeaderCell('Insured Name *', 110), + _buildHeaderCell('Vehicle No *', 90), + _buildHeaderCell('Action', 80), + // _buildHeaderCell('Assigned Date', 100), + // _buildHeaderCell('Premium', 100), + _buildHeaderCell('Payment Mode', 130), + _buildHeaderCell('Plan Type', 130), + + _buildHeaderCell('Policy', 120), + _buildHeaderCell('Status', 100), + ], + ), + ); + } + + Widget _buildHeaderCell(String label, double width) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 4), + child: SizedBox( + width: width, + child: Text( + label, + style: GoogleFonts.poppins( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Color(0xFF1E293B), + // color: Colors.black87, + ), + ), + ), + ); + } + + Widget _row(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + mainAxisSize: MainAxisSize.min, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: 70, + child: Text( + "$label ", + style: GoogleFonts.poppins( + color: Colors.black, + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ), + ), + + SizedBox( + width: 180, + child: Text( + value ?? '-', + softWrap: true, + maxLines: 5, + + style: GoogleFonts.poppins( + color: Colors.black, + fontSize: 10, + fontWeight: FontWeight.w400, + ), + ), + ), + ], + ), + ); + } + + static final _dataBold = GoogleFonts.inter( + fontSize: 11, + + fontWeight: FontWeight.w500, + color: Colors.black, + // color: Color(0xFF000000), + ); + static final _dataBoldthm1 = GoogleFonts.inter( + fontSize: 11, + + fontWeight: FontWeight.w500, + color: Colors.black, + // color: Color(0xFF000000), + ); + + static final _dataBoldthm2 = GoogleFonts.inter( + fontSize: 11, + fontWeight: FontWeight.w500, + // color: Colors.black, + color: Color(0XFF334155), + ); + static final _dataBoldthm3 = GoogleFonts.inter( + fontSize: 10, + fontWeight: FontWeight.w500, + // color: Colors.black, + color: Color(0XFF334155), + ); + static final _dataBoldthm4 = GoogleFonts.inter( + fontSize: 9, + fontWeight: FontWeight.w500, + // color: Colors.black, + color: Color(0XFF334155), + ); + final _tableDataTimeStyle = GoogleFonts.inter( + fontSize: 10, + fontWeight: FontWeight.w400, + color: Colors.black, + // color: Color(0XFF94A3B8), + ); + + final _subLabelTimeStyle = GoogleFonts.inter( + fontSize: 10, + fontWeight: FontWeight.w400, + color: Color(0XFF6366F1), + ); + static final _dataBoldsmall = GoogleFonts.inter( + fontSize: 12, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = GoogleFonts.inter( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + static final _headerStyle = GoogleFonts.inter( + // color: Colors.black, + color: Color(0xFF1E293B), + fontWeight: FontWeight.w500, + ); + static final _cardheaderStyle = GoogleFonts.inter( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static final TextStyle _textStyle = GoogleFonts.inter( + fontSize: 12, + fontWeight: FontWeight.w600, + ); + + static const _cardBodyStyle = TextStyle( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); + + String _truncateText(String text, int limit) { + if (text.length <= limit) return text; + return '${text.substring(0, limit)}...'; + } + + String _wrapText(String text, int chunkSize) { + if (text.isEmpty) return '-'; + final buffer = StringBuffer(); + for (int i = 0; i < text.length; i += chunkSize) { + int end = (i + chunkSize < text.length) ? i + chunkSize : text.length; + buffer.writeln(text.substring(i, end)); // adds '\n' after each chunk + } + return buffer.toString().trim(); + } + + String formatDateTimeForTable(String? input, {bool newLine = false}) { + if (input == null || input.trim().isEmpty) return '-'; + + final s = input.trim(); + DateTime dt; + + try { + // Case 1: ISO-like (yyyy-MM-dd ...), DateTime.parse will handle + if (RegExp(r'^\d{4}-\d{2}-\d{2}').hasMatch(s)) { + dt = DateTime.parse(s); + } + // Case 2: day-month-year at start (e.g. 13-11-2025 07:28 AM or 13-11-2025 07:28) + else if (RegExp(r'^\d{2}-\d{2}-\d{4}').hasMatch(s)) { + // Try with am/pm (hh:mm a) + if (RegExp(r'\b(am|pm)\b', caseSensitive: false).hasMatch(s)) { + dt = DateFormat('dd-MM-yyyy hh:mm a').parse(s); + } + // Try 24-hour time "dd-MM-yyyy HH:mm" or just date "dd-MM-yyyy" + else if (RegExp(r'^\d{2}-\d{2}-\d{4}\s+\d{1,2}:\d{2}').hasMatch(s)) { + dt = DateFormat('dd-MM-yyyy HH:mm').parse(s); + } else { + dt = DateFormat('dd-MM-yyyy').parse(s); + } + } + // Case 3: fallback — try parse with DateTime.parse (may throw) + else { + dt = DateTime.parse(s); + } + + final dateStr = DateFormat('dd-MM-yyyy').format(dt); + final timeStr = DateFormat('hh:mm a').format(dt); // e.g. 07:28 AM + + return newLine ? '$dateStr\n$timeStr' : '$dateStr | $timeStr'; + } catch (e) { + // If parsing fails, return original string as fallback (or '-' if empty) + return s.isNotEmpty ? s : '-'; + } + } +} diff --git a/lib/presentation/screens/staff/Enquiry/enquiry_inline_list.dart b/lib/presentation/screens/staff/Enquiry/enquiry_inline_list.dart index dc071a0..487a59d 100644 --- a/lib/presentation/screens/staff/Enquiry/enquiry_inline_list.dart +++ b/lib/presentation/screens/staff/Enquiry/enquiry_inline_list.dart @@ -13,6 +13,7 @@ import 'package:intl/intl.dart'; import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart'; import 'package:nhance_partner/presentation/screens/staff/Enquiry/quotationPopUpAccptReject.dart'; import 'package:nhance_partner/presentation/screens/staff/Enquiry/raise_enq_form.dart'; +import 'package:nhance_partner/presentation/screens/staff/Enquiry/staff_policy.dart'; import 'package:nhance_partner/presentation/screens/staff/Enquiry/tabs/tab.dart'; import 'package:nhance_partner/presentation/themes/indicators/customizd_multi_file_upload.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -134,6 +135,10 @@ class EnquiryStaffState extends ConsumerState { String? selectedId; + int selectedIndex = 0; + + final List enquiryTabs = ["In Progress", "Completed"]; + Map dataDetails() { final data = { "agent_id": @@ -211,7 +216,7 @@ class EnquiryStaffState extends ConsumerState { super.initState(); apiService = ApiService(); - timer = Timer.periodic(Duration(seconds: 3), (Timer t) => callRefresh()); + timer = Timer.periodic(Duration(seconds: 10), (Timer t) => callRefresh()); for (String field in tabHeader) { controllers[field] = TextEditingController(); } @@ -2420,77 +2425,77 @@ class EnquiryStaffState extends ConsumerState { buildPhNumber(context), buildRemarks(context), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Builder( - builder: (buttonContext) => Material( - // color: Color(0xFFFFFCF2), - color: Color(0xFFF8F9FF), - child: InkWell( - hoverColor: Color(0xFFF8F9FF), - // hoverColor: const Color(0xFFFFFCF2), - // hoverColor: const Color(0xFFEAF6F4), - onTap: () async { - // ✅ Get overlay and button position RELATIVE to InkWell - final RenderBox button = - buttonContext.findRenderObject() as RenderBox; - final RenderBox overlay = - Overlay.of(buttonContext).context.findRenderObject() - as RenderBox; - - final Offset position = button.localToGlobal( - Offset.zero, - ancestor: overlay, - ); - - await showMenu( - context: buttonContext, - position: RelativeRect.fromLTRB( - position.dx, - position.dy + button.size.height, - overlay.size.width, - 0, - ), - items: [ - PopupMenuItem( - child: Column( - mainAxisSize: MainAxisSize.min, - children: _buildPopupDownload( - buttonContext, - selectId, - ), - ), - ), - ], - // color: Colors.white, - // color: Color(0xFFFFFCF2), - color: Color(0xFFF8F9FF), - ); - }, - child: Tooltip( - message: 'Click To Upload Documents', - - waitDuration: const Duration(milliseconds: 500), - showDuration: const Duration(seconds: 2), - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(50), - ), - child: Icon( - Icons.upload_file, - color: Color(0XFF6366F1), - // editing ? Icons.upload_file : Icons.download_for_offline, - // color: editing ? Colors.b lue : Colors.green, - size: 20, - ), - ), - ), - ), - ), - ), - ), + // Padding( + // padding: const EdgeInsets.only(top: 8.0), + // child: Builder( + // builder: (buttonContext) => Material( + // // color: Color(0xFFFFFCF2), + // color: Color(0xFFF8F9FF), + // child: InkWell( + // hoverColor: Color(0xFFF8F9FF), + // // hoverColor: const Color(0xFFFFFCF2), + // // hoverColor: const Color(0xFFEAF6F4), + // onTap: () async { + // // ✅ Get overlay and button position RELATIVE to InkWell + // final RenderBox button = + // buttonContext.findRenderObject() as RenderBox; + // final RenderBox overlay = + // Overlay.of(buttonContext).context.findRenderObject() + // as RenderBox; + // + // final Offset position = button.localToGlobal( + // Offset.zero, + // ancestor: overlay, + // ); + // + // await showMenu( + // context: buttonContext, + // position: RelativeRect.fromLTRB( + // position.dx, + // position.dy + button.size.height, + // overlay.size.width, + // 0, + // ), + // items: [ + // PopupMenuItem( + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: _buildPopupDownload( + // buttonContext, + // selectId, + // ), + // ), + // ), + // ], + // // color: Colors.white, + // // color: Color(0xFFFFFCF2), + // color: Color(0xFFF8F9FF), + // ); + // }, + // child: Tooltip( + // message: 'Click To Upload Documents', + // + // waitDuration: const Duration(milliseconds: 500), + // showDuration: const Duration(seconds: 2), + // child: Container( + // padding: EdgeInsets.all(8.0), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(50), + // ), + // child: Icon( + // Icons.upload_file, + // color: Color(0XFF6366F1), + // // editing ? Icons.upload_file : Icons.download_for_offline, + // // color: editing ? Colors.b lue : Colors.green, + // size: 20, + // ), + // ), + // ), + // ), + // ), + // ), + // ), Padding( padding: const EdgeInsets.only(top: 8.0), child: IconButton( @@ -2863,36 +2868,40 @@ class EnquiryStaffState extends ConsumerState { // ], // ), width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.1, // padding: EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - RaiseEnqForm( - key: raiseEnqKey, - onSubmit: (dataSet) async { - print('Check checking dataSet $dataSet'); - try { - await createUserData(dataSet); // <-- API call here - print("Enquiry saved successfully"); - // RESET FORM - raiseEnqKey.currentState?.resetFormFields(); - } catch (e) { - showDialog( - context: context, - builder: (_) => AlertDialog( - title: const Text('Error'), - content: Text(e.toString()), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('OK'), - ), - ], - ), - ); - } - }, + Container( + // height: MediaQuery.of(context).size.height*0. + child: RaiseEnqForm( + key: raiseEnqKey, + onSubmit: (dataSet) async { + print('Check checking dataSet $dataSet'); + try { + await createUserData(dataSet); // <-- API call here + print("Enquiry saved successfully"); + // RESET FORM + raiseEnqKey.currentState?.resetFormFields(); + } catch (e) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: const Text('Error'), + content: Text(e.toString()), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('OK'), + ), + ], + ), + ); + } + }, + ), ), // SizedBox(height: 5), @@ -2920,29 +2929,29 @@ class EnquiryStaffState extends ConsumerState { ), // ), - Container( - // height: 20, - width: MediaQuery.of(context).size.width, - // color: Colors.green.shade50, - child: PaginationControls( - currentPage: currentPage, - itemsPerPage: itemsPerPage, - // totalItems: dataVal.length, - totalItems: filteredData.length, - // activeColor: layoutColor, // your theme color - onPageChanged: (page) { - setState(() { - currentPage = page; - }); - }, - onItemsPerPageChanged: (items) { - setState(() { - itemsPerPage = items; - currentPage = 1; - }); - }, - ), - ), + // Container( + // // height: 20, + // width: MediaQuery.of(context).size.width, + // // color: Colors.green.shade50, + // child: PaginationControls( + // currentPage: currentPage, + // itemsPerPage: itemsPerPage, + // // totalItems: dataVal.length, + // totalItems: filteredData.length, + // // activeColor: layoutColor, // your theme color + // onPageChanged: (page) { + // setState(() { + // currentPage = page; + // }); + // }, + // onItemsPerPageChanged: (items) { + // setState(() { + // itemsPerPage = items; + // currentPage = 1; + // }); + // }, + // ), + // ), ], ), ), @@ -2971,6 +2980,37 @@ class EnquiryStaffState extends ConsumerState { refrshfilterDateRange(); } + Future buildPolicyCreatedStatusActions( + BuildContext context, + status, + id, + ) async { + print("Actionsstatus - $status -$id"); + dynamic val; + if (status == 'Awaiting Proposal' || status == 'Proposal Created') { + val = ''; + } else { + val = 'Policy'; + } + + final result = await showDialog( + context: context, + barrierDismissible: + false, // optional - prevents closing by tapping outside + builder: (context) => PolicyStaffEnqList(), + ); + + // ✅ Code here runs *after* the dialog is closed + print("Dialog closed"); + print("Dialog result: $result"); + if (result) { + setState(() { + isActionable = false; + }); + refrshfilterDateRange(); + } + } + Widget _buildContent(BuildContext context) { final isDesktop = !ResponsiveLayout.isMobile(context); return Column( @@ -3076,8 +3116,8 @@ class EnquiryStaffState extends ConsumerState { ), ), - SizedBox(height: 5), - + // SizedBox(height: 5), + SizedBox(child: _buildStyledTabs()), ResponsiveLayout.isMobile(context) ? _buildDataTable(context) : @@ -3095,59 +3135,135 @@ class EnquiryStaffState extends ConsumerState { // 1. Add group expansion state tracking Map groupExpanded = { - 'Awaiting Proposal': true, - 'Proposal Created': true, + // 'Awaiting Proposal': true, + // 'Proposal Created': true, // 'Proposal Accepted': true, // 'Proposal Rejected': true, - 'Policy Created': true, + // 'Awaiting Payment': true, + // 'Policy Created': true, + 'To be assigned': true, + 'Assigned': true, + 'In progress': true, }; Map statusGroupMap = { - 'Awaiting Proposal': 'Awaiting Proposal', - 'Proposal Created': 'Proposal Created', - 'Proposal Accepted': 'Proposal Created', - 'Proposal Rejected': 'Proposal Created', - 'Policy Created': 'Policy Created', + // 'Awaiting Proposal': 'Awaiting Proposal', + // 'Proposal Created': 'Proposal Created', + // 'Proposal Accepted': 'Proposal Created', + // 'Proposal Rejected': 'Proposal Created', + // 'Proposal Created': 'Awaiting Payment', + // 'Proposal Accepted': 'Awaiting Payment', + // 'Proposal Rejected': 'Awaiting Payment', + // 'Policy Created': 'Policy Created', + // 'Policy Created': 'Policy Created', + 'To be assigned': 'To be assigned', + 'Assigned': 'Assigned', + 'In progress': 'In progress', }; + List> get filteredDataByTab { + if (selectedIndex == 0) { + // Progress enquiries + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + if (sortedData.isEmpty) return []; + return sortedData.where((e) { + return [ + "To be assigned", + "Assigned", + "In progress", + ].contains(e['enquiry_status']); + }).toList(); + } else { + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + if (sortedData.isEmpty) return []; + // Completed enquiries + return sortedData.where((e) { + return e['enquiry_status'] == "Completed"; + }).toList(); + } + } + // Add group enquiries by status Map>> get _groupedEnquiries { - final grouped = >>{}; + final Map>> grouped = {}; - // Initialize all status groups - grouped['Awaiting Proposal'] = []; - grouped['Proposal Created'] = []; - grouped['Proposal Accepted'] = []; - grouped['Proposal Rejected'] = []; - grouped['Policy Created'] = []; + if (selectedIndex == 0) { + grouped["To be assigned"] = []; + grouped["Assigned"] = []; + grouped["In progress"] = []; + } else { + grouped["Completed"] = []; + } - // Initialize only the groups you need - grouped['Awaiting Proposal'] = []; - grouped['Proposal Created'] = []; - grouped['Policy Created'] = []; - - // Group the filtered/paginated data by status - // for (var item in _paginatedData) { - // final status = item['status']?.toString() ?? 'Unknown'; - // if (grouped.containsKey(status)) { - // grouped[status]!.add(item); - // } - // } - - for (var item in _paginatedData) { - final status = item['status']?.toString() ?? 'Unknown'; - - // Map actual status to grouped status - final groupKey = statusGroupMap[status]; - - if (groupKey != null) { - grouped[groupKey]!.add(item); + for (var item in filteredDataByTab) { + final status = (item['enquiry_status'] ?? '').toString(); + if (grouped.containsKey(status)) { + grouped[status]!.add(item); } } return grouped; } + // Map>> get _groupedEnquiries { + // final grouped = >>{}; + // + // // Initialize all status groups + // // grouped['Awaiting Proposal'] = []; + // // grouped['Proposal Created'] = []; + // // grouped['Proposal Accepted'] = []; + // // grouped['Proposal Rejected'] = []; + // // grouped['Policy Created'] = []; + // // grouped['Awaiting Payment'] = []; + // + // // Initialize only the groups you need + // // grouped['Awaiting Proposal'] = []; + // // grouped['Proposal Created'] = []; + // // grouped['Policy Created'] = []; + // + // grouped['To be assigned'] = []; + // grouped['Assigned'] = []; + // grouped['In progress'] = []; + // + // // Group the filtered/paginated data by status + // // for (var item in _paginatedData) { + // // final status = item['status']?.toString() ?? 'Unknown'; + // // if (grouped.containsKey(status)) { + // // grouped[status]!.add(item); + // // } + // // } + // + // for (var item in filteredData) { + // // final status = item['status']?.toString() ?? 'Unknown'; + // final status = item['enquiry_status']?.toString() ?? 'Unknown'; + // + // // Map actual status to grouped status + // final groupKey = statusGroupMap[status]; + // + // if (groupKey != null) { + // grouped[groupKey]!.add(item); + // } + // } + // + // // for (var item in _paginatedData) { + // // // final status = item['status']?.toString() ?? 'Unknown'; + // // final status = item['enquiry_status']?.toString() ?? 'Unknown'; + // // + // // // Map actual status to grouped status + // // final groupKey = statusGroupMap[status]; + // // + // // if (groupKey != null) { + // // grouped[groupKey]!.add(item); + // // } + // // } + // + // return grouped; + // } + Map _getStatusConfig(String status) { switch (status) { case 'Awaiting Proposal': @@ -3170,7 +3286,12 @@ class EnquiryStaffState extends ConsumerState { 'Proposal Created': const Color(0xFFF0F9FF), // Cyan 50 'Proposal Accepted': const Color(0xFFF0FDF4), // Green 50 'Proposal Rejected': const Color(0xFFFEF9C3), // Yellow 50 - 'Policy Created': const Color(0xFFF3F0FF), // Purple 50 (generated) + 'Policy Created': const Color(0xFFF3F0FF), + + 'To be assigned': const Color(0xFFEFF6FF), // Blue 50 + 'Assigned': const Color(0xFFFEF9C3), // Cyan 50 + 'In progress': const Color(0xFFF0FDF4), // Green 50 + 'Completed': const Color(0xFFF3F0FF), // Purple 50 (generated) }; final Map statusBorderColors = { @@ -3179,6 +3300,11 @@ class EnquiryStaffState extends ConsumerState { 'Proposal Accepted': const Color(0xFFDCFCE7), // Green 100 'Proposal Rejected': const Color(0xFFFEF3C7), // Yellow 100 'Policy Created': const Color(0xFFF0E4FF), // Purple 200 + + 'To be assigned': const Color(0xFFDBEAFE), // Blue 100 + 'Assigned': const Color(0xFFFEF3C7), // Cyan 100 + 'In progress': const Color(0xFFDCFCE7), // Green 100 + 'Completed': const Color(0xFFF0E4FF), // Purple 200 // 'Policy Created': const Color(0xFFE5CCFF), // Purple 200 }; @@ -3202,7 +3328,7 @@ class EnquiryStaffState extends ConsumerState { }); }, child: Container( - padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4), + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 2), child: Row( children: [ Icon( @@ -3348,6 +3474,8 @@ class EnquiryStaffState extends ConsumerState { mainAxisSize: MainAxisSize.min, children: [ // Group Header + // if (status != 'Proposal Accepted' && + // status != 'Proposal Rejected') ...[ if (status != 'Proposal Accepted' && status != 'Proposal Rejected') ...[ Container( @@ -3487,7 +3615,8 @@ class EnquiryStaffState extends ConsumerState { final editing = isEditingRow[id] ?? false; final controllers = rowControllers[id]; - String status = item['status'] ?? '-'; + // String status = item['status'] ?? '-'; + String status = item['enquiry_status'] ?? '-'; Color bgColor = statusColors[status] ?? Color(0xFFF9FAFB); Color borderColor = statusBorderColors[status] ?? Color(0xFFE2E8F0); @@ -3774,6 +3903,91 @@ class EnquiryStaffState extends ConsumerState { ), ), + DataCell( + SizedBox( + width: 120, + + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (item['enquiry_status'] != 'Assigned') ...[ + Material( + color: Colors.white, + child: InkWell( + // hoverColor: Color(0xFFEAF6F4), + onTap: null, + // onTap: () async { + // setState(() { + // isActionable = true; + // }); + // buildPolicyCreatedStatusActions( + // context, + // item['status'], + // item['id'], + // ); + // }, + child: Tooltip( + message: 'Click to View or Process Enquiry', // + waitDuration: const Duration( + milliseconds: 500, + ), // optional + showDuration: const Duration(seconds: 2), // optional + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.0), + margin: EdgeInsets.symmetric(vertical: 2), + decoration: BoxDecoration( + // color: Color(0xFFF9FAFB), + // border: Border.all(color: Color(0xFFE2E8F0)), + color: bgColor, + border: Border.all(color: borderColor), + borderRadius: BorderRadius.circular(5), + ), + + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + item['enquiry_status'] ?? '-', + // item['status'] ?? '-', + style: GoogleFonts.inter( + fontSize: 10, + color: Color(0XFF1e293b), + // color: statusTextColors[status] ?? Colors.black, + fontWeight: FontWeight.w500, + ), + // overflow: TextOverflow.clip, // + ), + ], + ), + ), + ), + // child: Text(item['status'] ?? '-', style: _dataBold), + ), + ), + ], + if (item['enquiry_status'] == 'Assigned') ...[ + TextButton( + onPressed: () async { + final res = await apiService.updateEnquiryInProgress(id); + if (res['status'] == 'success') { + refrshfilterDateRange(); + } + print('updateEnquiryInProgress - $res'); + }, + child: Text( + 'PROCEED', + style: GoogleFonts.poppins( + fontSize: 11, + fontWeight: FontWeight.w500, + color: Colors.green, + ), + ), + ), + ], + ], + ), + ), + ), // Assigned Date (formatted) // DataCell( // SizedBox( @@ -4285,65 +4499,65 @@ class EnquiryStaffState extends ConsumerState { ), ), - DataCell( - SizedBox( - width: 120, - - child: Material( - color: Colors.white, - child: InkWell( - // hoverColor: Color(0xFFEAF6F4), - onTap: () async { - var status = item['status']; - var enqId = item['id']; - - final prefs = await SharedPreferences.getInstance(); - - // ✅ Remove old value (if any) - await prefs.remove('enqStaffDataId'); - - // ✅ Save the new id - await prefs.setString('enqStaffDataId', enqId.toString()); - ref.read(quotationStaffIdProvider.notifier).state = enqId; - buildStatusActions(context, status, enqId); - }, - child: Tooltip( - message: 'Click to View or Process Enquiry', // - waitDuration: const Duration(milliseconds: 500), // optional - showDuration: const Duration(seconds: 2), // optional - child: Container( - padding: EdgeInsets.symmetric(vertical: 2.0), - margin: EdgeInsets.symmetric(vertical: 2), - decoration: BoxDecoration( - // color: Color(0xFFF9FAFB), - // border: Border.all(color: Color(0xFFE2E8F0)), - color: bgColor, - border: Border.all(color: borderColor), - borderRadius: BorderRadius.circular(5), - ), - - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - item['status'] ?? '-', - style: GoogleFonts.inter( - fontSize: 10, - color: Color(0XFF1e293b), - // color: statusTextColors[status] ?? Colors.black, - fontWeight: FontWeight.w500, - ), - // overflow: TextOverflow.clip, // - ), - ], - ), - ), - ), - // child: Text(item['status'] ?? '-', style: _dataBold), - ), - ), - ), - ), + // DataCell( + // SizedBox( + // width: 120, + // + // child: Material( + // color: Colors.white, + // child: InkWell( + // // hoverColor: Color(0xFFEAF6F4), + // onTap: () async { + // var status = item['status']; + // var enqId = item['id']; + // + // final prefs = await SharedPreferences.getInstance(); + // + // // ✅ Remove old value (if any) + // await prefs.remove('enqStaffDataId'); + // + // // ✅ Save the new id + // await prefs.setString('enqStaffDataId', enqId.toString()); + // ref.read(quotationStaffIdProvider.notifier).state = enqId; + // buildStatusActions(context, status, enqId); + // }, + // child: Tooltip( + // message: 'Click to View or Process Enquiry', // + // waitDuration: const Duration(milliseconds: 500), // optional + // showDuration: const Duration(seconds: 2), // optional + // child: Container( + // padding: EdgeInsets.symmetric(vertical: 2.0), + // margin: EdgeInsets.symmetric(vertical: 2), + // decoration: BoxDecoration( + // // color: Color(0xFFF9FAFB), + // // border: Border.all(color: Color(0xFFE2E8F0)), + // color: bgColor, + // border: Border.all(color: borderColor), + // borderRadius: BorderRadius.circular(5), + // ), + // + // child: Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text( + // item['status'] ?? '-', + // style: GoogleFonts.inter( + // fontSize: 10, + // color: Color(0XFF1e293b), + // // color: statusTextColors[status] ?? Colors.black, + // fontWeight: FontWeight.w500, + // ), + // // overflow: TextOverflow.clip, // + // ), + // ], + // ), + // ), + // ), + // // child: Text(item['status'] ?? '-', style: _dataBold), + // ), + // ), + // ), + // ), ], ); } @@ -4360,12 +4574,12 @@ class EnquiryStaffState extends ConsumerState { DataColumn(label: Text('Insured Name *', style: _headerStyle)), DataColumn(label: Text('Vehicle No *', style: _headerStyle)), DataColumn(label: Text('Action', style: _headerStyle)), + DataColumn(label: Text('Status', style: _headerStyle)), // const DataColumn(label: Text('Assigned Date', style: _headerStyle)), // DataColumn(label: Text('Premium', style: _headerStyle)), DataColumn(label: Text('Payment Mode', style: _headerStyle)), DataColumn(label: Text('Plan Type', style: _headerStyle)), - DataColumn(label: Text('Policy Number', style: _headerStyle)), - DataColumn(label: Text('Status', style: _headerStyle)), + DataColumn(label: Text('Policy', style: _headerStyle)), ]; } @@ -4383,14 +4597,14 @@ class EnquiryStaffState extends ConsumerState { _buildHeaderCell('Insurer *', 90), _buildHeaderCell('Insured Name *', 110), _buildHeaderCell('Vehicle No *', 90), - _buildHeaderCell('Action', 80), + _buildHeaderCell('Action', 110), + _buildHeaderCell('Status', 100), // _buildHeaderCell('Assigned Date', 100), // _buildHeaderCell('Premium', 100), _buildHeaderCell('Payment Mode', 130), _buildHeaderCell('Plan Type', 130), - _buildHeaderCell('Policy Number', 120), - _buildHeaderCell('Status', 100), + _buildHeaderCell('Policy', 120), ], ), ); @@ -4452,6 +4666,76 @@ class EnquiryStaffState extends ConsumerState { ); } + Widget _buildStyledTabs() { + return Container( + padding: const EdgeInsets.symmetric(vertical: 4), + decoration: const BoxDecoration( + color: Colors.white, + // color: Colors.amber, + // border: Border(bottom: BorderSide(color: Color(0xFFE5E5E5), width: 1)), + ), + child: Row( + children: List.generate(enquiryTabs.length, (index) { + final bool isSelected = selectedIndex == index; + + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + setState(() { + selectedIndex = index; + }); + }, + child: AnimatedContainer( + duration: const Duration(milliseconds: 250), + curve: Curves.easeOut, + padding: const EdgeInsets.symmetric( + vertical: 5, + horizontal: 20, + ), + margin: const EdgeInsets.only(right: 24), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6), + color: isSelected + ? const Color(0xFF2E7D6E).withOpacity(0.08) + : Colors.transparent, + ), + child: Column( + // mainAxisSize: MainAxisSize.min, + children: [ + Text( + enquiryTabs[index], + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: isSelected + ? const Color(0xFF2E7D6E) + : Colors.black87, + ), + ), + + // const SizedBox(height: 3), + + // ▬▬ Underline Indicator ▬▬ + AnimatedContainer( + duration: const Duration(milliseconds: 250), + height: 3, + width: isSelected ? 40 : 0, + decoration: BoxDecoration( + color: const Color(0xFF2E7D6E), + borderRadius: BorderRadius.circular(50), + ), + ), + ], + ), + ), + ), + ); + }), + ), + ); + } + static final _dataBold = GoogleFonts.inter( fontSize: 11, diff --git a/lib/presentation/screens/staff/Enquiry/raise_enq_form.dart b/lib/presentation/screens/staff/Enquiry/raise_enq_form.dart index eec960d..fe69e60 100644 --- a/lib/presentation/screens/staff/Enquiry/raise_enq_form.dart +++ b/lib/presentation/screens/staff/Enquiry/raise_enq_form.dart @@ -381,28 +381,30 @@ class RaiseEnqFormState extends ConsumerState { ), ], ), - child: Form( - key: _formKey, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - buildAgentName(context, fromHeader: true), - if (roleId != 'staff') ...[buildSelectStaffMem(context)], + child: FocusTraversalGroup( + child: Form( + key: _formKey, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + buildAgentName(context, fromHeader: true), + if (roleId != 'staff') ...[buildSelectStaffMem(context)], - buildBroker(context), - buildInsurer(context, fromHeader: true), + buildBroker(context), + buildInsurer(context, fromHeader: true), - // buildInsuredName(context, fromHeader: true), - buildVehicleNumber(context), - Row( - children: [ - buildRefresh(context), - SizedBox(width: 5), - buildSave(context), - ], - ), - ], + // buildInsuredName(context, fromHeader: true), + buildVehicleNumber(context), + Row( + children: [ + buildRefresh(context), + SizedBox(width: 5), + buildSave(context), + ], + ), + ], + ), ), ), ); diff --git a/lib/presentation/screens/staff/Enquiry/staff_policy.dart b/lib/presentation/screens/staff/Enquiry/staff_policy.dart new file mode 100644 index 0000000..7b3764f --- /dev/null +++ b/lib/presentation/screens/staff/Enquiry/staff_policy.dart @@ -0,0 +1,3039 @@ +import 'dart:convert'; + +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/screens/Enquiry/enquiry/policy_popup.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../../../core/config/env.dart'; +import '../../../../core/routing/routes.dart'; +import '../../../../core/services/api_service.dart'; +import '../../../../data/services/auth_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../../data/utils/toastNotification.dart'; +import '../../../../data/utils/validators.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../providers/quotation_staff_proivder.dart'; +import '../../../providers/userRoleProvider.dart'; +import '../../../themes/indicators/custom_loader.dart'; +import '../../../themes/indicators/customizd_file_upload.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 '../../../themes/indicators/text_field_theme.dart'; +import '../../../widgets/custom_action_popup.dart'; +import '../../Enquiry/policy_claims_endros/sub_claims.dart'; +import '../../Enquiry/policy_claims_endros/sub_endrosment.dart'; + +class PolicyStaffEnqList extends ConsumerStatefulWidget { + // final List>? data; + // dynamic id; + // PolicyStaffEnqList({super.key, this.data, this.id}); + PolicyStaffEnqList({super.key}); + @override + ConsumerState createState() => PolicyStaffEnqListState(); +} + +class PolicyStaffEnqListState extends ConsumerState { + int currentPage = 0; + int itemsPerPage = 10; + + List> dataVal = []; + + final TextEditingController _searchController = TextEditingController(); + + late ApiService apiService; + final _formKey = GlobalKey(); + final GlobalKey>> dropDownKey = + GlobalKey>>(); + + final GlobalKey>> dropDownKeyBroker = + GlobalKey>>(); + + final GlobalKey>> dropDownKeyAgent = + GlobalKey>>(); + + final GlobalKey>> + dropDownKeyInsurerEnqAsgn = + GlobalKey>>(); + + List> getBrokerData = []; + List> filteredBrokerData = []; + String? selectedBroker; + String? selectedBrokerName; + String? selectedAgent; + String? selectedInsurer; + + List> getAgentListData = []; + List> filteredAgentData = []; + + List tabHeader = [ + 'name', + 'email', + 'mobile', + 'code', + 'address', + 'regNo', + + 'insurer', + 'regNum', + 'idv', + 'premium_amount', + 'planType', + 'policyInsName', + 'policyPremiumAmount', + 'policyIdv', + 'policyNumber', + 'policyPaymentMode', + 'issueDate', + 'startDate', + 'endDate', + + 'tp', + 'od', + 'pa', + 'cgst', + 'sgst', + 'igst', + 'rto_state_code', + 'rto_city_code', + 'weight', + 'fuel_type', + 'date_of_registration', + 'year_of_manufacture', + 'engine_no', + 'chassis_no', + 'make', + 'model', + 'cubic_capacity', + 'vehicle_type', + 'premiumTOT', + 'commison_amount', + 'commison_applied_rule', + ]; + late String isActive = "1"; + PlatformFile? docUploadedFile; + PlatformFile? docPDFUploadedFile; + + // PlatformFile? passportFile; + String? selectedFileNames; + String? selectedPDFFileNames; + String? passportFileUrlFromApi; + String? docUploadedFileUrlFromApi; + String? docUploadedPDFFileUrlFromApi; + + String? selectedId; + bool isLoading = false; + bool isquotation = false; + bool hasPolicyData = false; + + Map controllers = {}; + String? _token; + dynamic userId; + dynamic managerId; + dynamic enqQuotation; + dynamic selectedEnquiryId; + dynamic acceptedQuotationId; + dynamic choosedPolcyId; + + dynamic roleId; + dynamic enqBrokerName; + dynamic selectedPaymentMode; + + List> getVehicleTypeData = []; + List> filteredVechicleData = []; + + List> getInsurersData = []; + List> filteredInsurersData = []; + + late Map enquiryData; + late Map policyData; + Map? quotationAcceptedData; + + Map dataDetails() { + final data = { + "quotation_id": acceptedQuotationId, + "insured_name": controllers["policyInsName"]?.text, + "issued_date": controllers["issueDate"]?.text, + "start_date": controllers["startDate"]?.text, + "end_date": controllers["endDate"]?.text, + // "premium_amount": controllers["premium_amount"]?.text, + // "premium_amount": controllers["policyPremiumAmount"]?.text, + "policy_number": controllers["policyNumber"]?.text, + "payment_mode": controllers["policyPaymentMode"]?.text, + "broker_id": selectedBroker, + "tp": controllers["tp"]?.text, + "od": controllers["od"]?.text, + "pa": controllers["pa"]?.text, + "cgst": controllers["cgst"]?.text, + "sgst": controllers["sgst"]?.text, + "igst": controllers["igst"]?.text, + "premium_amount": controllers["premiumTOT"]?.text, + "manager_id": managerId, + // "policy_pdf_file_name": "policy_doc.pdf", + // "policy_payment_receipt_file_name": "receipt_doc.pdf", + // "created_by": userId, + }; + return data; + } + + Map dataForPolicyPDFDetails() { + final data = {"quotation_id": acceptedQuotationId, "manager_id": managerId}; + return data; + } + + List> quotationData = []; + List> originalData = []; + List> filteredData = []; + bool isLoader = false; + + @override + void initState() { + super.initState(); + apiService = ApiService(); + + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + + // Add listeners to text fields + controllers["tp"]?.addListener(calculateAmount); + controllers["od"]?.addListener(calculateAmount); + controllers["pa"]?.addListener(calculateAmount); + controllers["cgst"]?.addListener(calculateAmount); + controllers["sgst"]?.addListener(calculateAmount); + controllers["igst"]?.addListener(calculateAmount); + + // updateData(); + _initializeToken(); + // Future.microtask(() { + // managerId = ref.watch(managerIdProvider); + // userId = ref.watch(userIdProvider); + // + // getQuotationList(managerId); + // }); + + if (kIsWeb) { + Future.microtask(() => _restoreManagerId(ref)); + } + + Future.microtask(() { + managerId = ref.read(managerIdProvider); // ✅ use read + userId = ref.read(userIdProvider); // ✅ use read + roleId = ref.read(userRoleProvider); // ✅ use read + enqBrokerName = ref.read(enqBrokerNameProvider); + + print('QmanagerId - $managerId'); + print('QuserId - $userId'); + enqQuotation = ref.read(quotationStaffIdProvider); // ✅ use read + print('QenqQuotation - $enqQuotation'); + + controllers["cgst"]?.text = '0'; + controllers["sgst"]?.text = '0'; + controllers["igst"]?.text = '0'; + getBroker(); + getInsurers(); + if (enqQuotation != null) { + _loadData(enqQuotation); + } + + if (managerId != null) { + print('managerId - $managerId'); + getAgentList(managerId); + } + }); + } + + Future _restoreManagerId(WidgetRef ref) async { + final prefs = await SharedPreferences.getInstance(); + + final String? savedId = prefs.getString('enqStaffDataId'); + final String? savedBrokerName = prefs.getString( + 'enqBrokerName', + ); // already a string + + if (savedBrokerName != null) { + ref.read(enqBrokerNameProvider.notifier).state = savedBrokerName; + } + + if (savedId != null) { + ref.read(quotationStaffIdProvider.notifier).state = savedId; + print("savedenqStaffDataId ID restored: $savedId"); + + _loadData(savedId); + } + } + + void calculateAmount() { + print('calculateAmount 1'); + setState(() { + double tp = double.tryParse(controllers["tp"]?.text ?? '0') ?? 0; + double od = double.tryParse(controllers["od"]?.text ?? '0') ?? 0; + double pa = double.tryParse(controllers["pa"]?.text ?? '0') ?? 0; + double cgst = double.tryParse(controllers["cgst"]?.text ?? '0') ?? 0; + double sgst = double.tryParse(controllers["sgst"]?.text ?? '0') ?? 0; + double igst = double.tryParse(controllers["igst"]?.text ?? '0') ?? 0; + + double total = tp + od + pa + cgst + sgst + igst; + + print('Val : $total'); + controllers["premiumTOT"]!.text = total.toStringAsFixed(2); + }); + } + + @override + void dispose() { + // Dispose all TextEditingControllers + for (var controller in controllers.values) { + controller.dispose(); + } + super.dispose(); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + Future _loadData(enqQuotation) async { + getQuotationList(enqQuotation); + } + + Future getQuotationList(enqQuotation) async { + print('getClaimList called enqQuotation- $enqQuotation'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.findEnqQuotePolicyView(enqQuotation); + + if (response['status'] == 'success') { + print('quoationListData - ${response['data']}'); + setState(() { + enquiryData = Map.from(response['data']['enquiry']); + print('enquiryData - ${enquiryData}'); + + updateEnquiryData(enquiryData); + // quotationData = List>.from(response['data']); + quotationData = List>.from( + response['data']['quotations'], + ); + print('quotationData - ${quotationData}'); + updateQuotationData(quotationData); + + policyData = Map.from(response['data']['policies']); + + print('policyData - ${policyData}'); + + updatePolicyData(policyData); + originalData = quotationData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + quotationData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getAgentList(id) async { + print('getAgentListData called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchAgentNameDropDown(id); + print('getAgentListData called response'); + print('get Agent- ${response['data']}'); + if (response['status'] == 'success') { + print('get Agent- ${response['data']}'); + setState(() { + getAgentListData = List>.from(response['data']); + print('API Data - $getAgentListData'); + + filteredAgentData = List.from(getAgentListData); + print('originalAgentData - $filteredAgentData'); + }); + } else { + getAgentListData = []; + filteredAgentData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getInsurers() async { + print('Insurers called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('Insurers'); + + if (response['status'] == 200) { + print('getInsurers - ${response['data']}'); + setState(() { + getInsurersData = List>.from(response['data']); + print('API Data - $getInsurersData'); + + filteredInsurersData = List.from(getInsurersData); + print('originalData - $filteredInsurersData'); + }); + } else { + getInsurersData = []; + filteredInsurersData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + Future getBroker() async { + print('getBroker called'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchMasterDropDown('Broker'); + + if (response['status'] == 200) { + print('getBroker - ${response['data']}'); + setState(() { + getBrokerData = List>.from(response['data']); + print('API Data - $getBrokerData'); + + filteredBrokerData = List.from(getBrokerData); + print('originalData - $filteredBrokerData'); + }); + } else { + getBrokerData = []; + filteredBrokerData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + void updateEnquiryData(enquiryData) { + setState(() { + selectedEnquiryId = enquiryData['id']; + print('selectedEnquiryId- $selectedEnquiryId'); + controllers["regNum"]?.text = enquiryData['reg_no']; + controllers["insurer"]?.text = enquiryData['insurer_name']; + controllers["policyInsName"]?.text = enquiryData['name']; + }); + } + + void updateQuotationData(List> quotationData) { + try { + final acceptedItem = quotationData.firstWhere( + (item) => item['status'] == 'Accepted', + ); + + quotationAcceptedData = acceptedItem; + print('AcceptedData YYY - $quotationAcceptedData'); + + if (quotationAcceptedData != null) { + if (!mounted) return; + print('AcceptedData YYY2'); + setState(() { + controllers["insurer"]?.text = quotationAcceptedData?['insurer_name']; + acceptedQuotationId = quotationAcceptedData?['id']?.toString() ?? ''; + controllers["idv"]?.text = + quotationAcceptedData?['insured_declared_value']?.toString() ?? + ''; + controllers["premium_amount"]?.text = + quotationAcceptedData?['premium_amount']?.toString() ?? ''; + controllers["planType"]?.text = + quotationAcceptedData?['insurance_plan_type']?.toString() ?? ''; + controllers["policyPaymentMode"]?.text = + quotationAcceptedData?['payment_mode_value']?.toString() ?? ''; + selectedBroker = quotationAcceptedData?['broker_id'] ?? ''; + selectedBrokerName = quotationAcceptedData?['broker_name'] ?? ''; + }); + } + } catch (e) { + quotationAcceptedData = null; + print('No Accepted quotation found'); + } + } + + String fixInvalidDate(dynamic value) { + if (value == null) return ''; + final str = value.toString(); + + // Check for your invalid date patterns + if (str.contains('--0001') || str == '30-11--0001' || str == '0000-00-00') { + return ''; + } + return str; + } + + void updatePolicyData(Map policyData) { + print("updatePolicyDataupdatePolicyData - $policyData"); + + if (!mounted || policyData.isEmpty) return; + + setState(() { + hasPolicyData = true; + choosedPolcyId = policyData['id']?.toString() ?? ''; + controllers["policyInsName"]?.text = + policyData['insured_name']?.toString() ?? ''; + controllers["idv"]?.text = + policyData['insured_declared_value']?.toString() ?? ''; + controllers["policyPremiumAmount"]?.text = + policyData['premium_amount']?.toString() ?? ''; + controllers["planType"]?.text = + policyData['insurance_plan_type']?.toString() ?? ''; + controllers["policyNumber"]?.text = + policyData['policy_number']?.toString() ?? ''; + controllers["policyPaymentMode"]?.text = + policyData['payment_mode']?.toString() ?? ''; + selectedPaymentMode = policyData['payment_mode_value']?.toString() ?? ''; + controllers["issueDate"]?.text = fixInvalidDate( + policyData['issued_date'], + ); + controllers["startDate"]?.text = fixInvalidDate(policyData['start_date']); + controllers["endDate"]?.text = fixInvalidDate(policyData['end_date']); + + // controllers["issueDate"]?.text = + // policyData['issued_date']?.toString() ?? ''; + // controllers["startDate"]?.text = + // policyData['start_date']?.toString() ?? ''; + // controllers["endDate"]?.text = policyData['end_date']?.toString() ?? ''; + + controllers["tp"]?.text = policyData['tp']?.toString() ?? ''; + controllers["od"]?.text = policyData['od']?.toString() ?? ''; + controllers["pa"]?.text = policyData['pa']?.toString() ?? ''; + + controllers["cgst"]?.text = policyData['cgst']?.toString() ?? ''; + controllers["sgst"]?.text = policyData['sgst']?.toString() ?? ''; + controllers["igst"]?.text = policyData['igst']?.toString() ?? ''; + controllers["premiumTOT"]?.text = + policyData['premium_amount']?.toString() ?? ''; + + selectedBroker = policyData['broker_id'] ?? ''; + selectedBrokerName = policyData['broker_name'] ?? ''; + // RC FILE + String? rcPath = policyData["policy_pdf_file_name"]; + if (rcPath != null && rcPath.isNotEmpty) { + selectedPDFFileNames = rcPath.split('/').last; // UI filename + docUploadedPDFFileUrlFromApi = rcPath; // API download URL + docPDFUploadedFile = null; + // docUploadedRCFile = + // rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet + } else { + selectedPDFFileNames = null; // no UI file shown + docUploadedPDFFileUrlFromApi = null; + docPDFUploadedFile = null; + } + + // ID PROOF FILE + String? idProofPath = policyData["policy_payment_receipt_file_name"]; + if (idProofPath != null && idProofPath.isNotEmpty) { + selectedFileNames = idProofPath.split('/').last; + docUploadedFileUrlFromApi = idProofPath; // ✅ FIXED → correct variable + docUploadedFile = null; + // docUploadedIDProof = idProofFileUrlFromApi as PlatformFile?; + } else { + selectedFileNames = null; + docUploadedFileUrlFromApi = null; + docUploadedFile = null; + } + }); + } + + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat('dd-MM-yyyy').format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } + + void updateUploadPDFPolicyData(Map policyData) { + print('updateUploadPDFPolicyDataJJ - $policyData'); + if (!mounted || policyData.isEmpty) return; + + setState(() { + hasPolicyData = true; + choosedPolcyId = policyData['id']?.toString() ?? ''; + + controllers["policyNumber"]?.text = + policyData['policy_number']?.toString() ?? ''; + controllers["policyPaymentMode"]?.text = + policyData['payment_mode_value']?.toString() ?? ''; + selectedPaymentMode = policyData['payment_mode_value']?.toString() ?? ''; + + controllers["issueDate"]?.text = + _formatDate(policyData['issued_date']!.toString()) ?? ''; + controllers["startDate"]?.text = + _formatDate(policyData['start_date']!.toString()) ?? ''; + controllers["endDate"]?.text = + _formatDate(policyData['end_date']!.toString()) ?? ''; + + final premium = policyData['premium']; + if (premium != null) { + final taxes = premium['taxes'] ?? {}; + controllers["tp"]?.text = premium["tp"]?.toString() ?? '0'; + controllers["od"]?.text = premium["od"]?.toString() ?? '0'; + controllers["pa"]?.text = premium["pa"]?.toString() ?? '0'; + controllers["cgst"]?.text = taxes["cgst"]?.toString() ?? '0'; + controllers["sgst"]?.text = taxes["sgst"]?.toString() ?? '0'; + controllers["igst"]?.text = taxes["igst"]?.toString() ?? '0'; + controllers["premiumTOT"]?.text = premium["total"]?.toString() ?? '0'; + } + + // RC FILE + String? rcPath = policyData["policy_pdf_file_name"]; + if (rcPath != null && rcPath.isNotEmpty) { + selectedPDFFileNames = rcPath.split('/').last; // UI filename + docUploadedPDFFileUrlFromApi = rcPath; // API download URL + docPDFUploadedFile = null; + // docUploadedRCFile = + // rcFileUrlFromApi as PlatformFile?; // user has not re-uploaded yet + } else { + selectedPDFFileNames = null; // no UI file shown + docUploadedPDFFileUrlFromApi = null; + docPDFUploadedFile = null; + } + }); + } + + void handleSave() { + // if (!_formKey.currentState!.validate()) return; + setState(() { + // if (_formKey.currentState!.validate()) { + calculateAmount(); + dataDetails(); + final dataSet = dataDetails(); + print("dataSetPolicy - $dataSet"); + + final bool isUpdating = choosedPolcyId != null; + + // if (!isUpdating && selectedBrokerName == 'Nhance') { + // // if (!isUpdating && enqBrokerName == 'Nhance') { + // ToastHelper.showErrorToast(context, "Policy PDF is required"); + // return; + // } + // (enqBrokerName != 'Nhance') + // File validations + if ( + // (selectedBrokerName != 'Nhance') && + (docPDFUploadedFile == null || docPDFUploadedFile?.bytes == null) && + (docUploadedPDFFileUrlFromApi == null || + docUploadedPDFFileUrlFromApi!.isEmpty)) { + ToastHelper.showErrorToast(context, "Policy PDF is required"); + return; + } + createUserData(dataSet); + // } else { + // // isDi sable = false; + // } + }); + } + + void handleUploadPolicy() { + setState(() { + dataForPolicyPDFDetails(); + final dataSet = dataForPolicyPDFDetails(); + print("dataSetPolicy - $dataSet"); + // File validations + if ((docPDFUploadedFile == null || docPDFUploadedFile?.bytes == null) && + (docUploadedPDFFileUrlFromApi == null || + docUploadedPDFFileUrlFromApi!.isEmpty)) { + ToastHelper.showErrorToast(context, "Policy PDF is required"); + return; + } + createPolicyPDFData(dataSet); + }); + } + + Future attachFiles(http.MultipartRequest request) async { + Future addFileOrKeepName( + PlatformFile? file, + String? apiFileName, + String fieldName, + ) async { + if (file != null) { + // User uploaded a new file → send as multipart + if (file.bytes != null) { + request.files.add( + http.MultipartFile.fromBytes( + fieldName, + file.bytes!, + filename: file.name, + ), + ); + } else if (file.path != null) { + request.files.add( + await http.MultipartFile.fromPath( + fieldName, + file.path!, + filename: file.name, + ), + ); + } + print("📎 Attached new file → $fieldName"); + } else if (apiFileName != null && apiFileName.isNotEmpty) { + // No new upload → tell backend to keep old file + request.fields[fieldName] = apiFileName; + print("🔗 Kept old file → $fieldName = $apiFileName"); + } else { + // Nothing at all + request.fields[fieldName] = ""; + } + } + + await addFileOrKeepName( + docPDFUploadedFile, + docUploadedPDFFileUrlFromApi, + 'policy_pdf_file_name', + ); + // await addFileOrKeepName( + // docUploadedFile, + // docUploadedFileUrlFromApi, + // 'policy_payment_receipt_file_name', + // ); + } + + Future createUserData(Map userData) async { + final bool isUpdating = choosedPolcyId != null; + final id = choosedPolcyId; + // final id = '1'; + // print('UPDId- $id'); + + // final bool isUpdating = false; + final uri = Uri.parse( + isUpdating + ? '${Env.apiUrl}policy/updatePolicy' + : '${Env.apiUrl}policy/createPolicy', + ); + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + // Use MultipartRequest (POST only) + final request = http.MultipartRequest('POST', uri); + request.headers['Authorization'] = 'Bearer $_token'; + request.headers['app-signature'] = Env.App_Signature; + + // If updating, spoof the method Laravel-style + if (isUpdating) { + request.fields['id'] = id!; + request.fields['updated_by'] = userId!.toString(); + } else { + request.fields['created_by'] = userId!.toString(); + } + + print("USerDAta - $userData"); + + // userData.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + await attachFiles(request); + userData.forEach((key, value) { + if (key != 'policy_pdf_file_name' + // && + // key != 'policy_payment_receipt_file_name' + ) { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + } else { + print('Something Missing..'); + } + }); + + // attach files + + // request.fields['agent_id'] = selectedId.toString(); + + print(" Sending request with fields: ${request.fields}"); + + try { + final streamedResponse = await request.send(); + final response = await http.Response.fromStream(streamedResponse); + print("Response status: ${response.statusCode}"); + print("Response body: ${response.body}"); + + if (response.statusCode == 200 || response.statusCode == 201) { + // dispose(); + print("✅ Agent submitted successfully!"); + ToastHelper.showSuccessToast(context, 'Saved Policy'); + print("Response: ${response.body}"); + + Navigator.pop(context); + if (isUpdating) { + ref.read(enquiryIdProvider.notifier).state = null; + context.go(AppRoutes.enquiryForStaff); + } else { + ref.read(enquiryIdProvider.notifier).state = null; + context.go(AppRoutes.enquiryForStaff); + } + } else if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + } else { + print("❌ Submission failed. Status: ${response.statusCode}"); + print("Body: ${response.body}"); + + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text("Policy Creation Failed"), + content: Text( + "There was a problem in creating policy. Please try again.", + ), + actions: [ + TextButton( + child: Text("OK"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } + } + + Future createPolicyPDFData(Map userData) async { + final bool isUpdating = choosedPolcyId != null; + final id = choosedPolcyId; + // final id = '1'; + // print('UPDId- $id'); + + final uri = Uri.parse('${Env.apiUrl}policy/uploadPolicyFile'); + if (_token == null) { + throw Exception('Token not found. Please log in.'); + } + + // Use MultipartRequest (POST only) + final request = http.MultipartRequest('POST', uri); + request.headers['Authorization'] = 'Bearer $_token'; + request.headers['app-signature'] = Env.App_Signature; + + // If updating, spoof the method Laravel-style + if (isUpdating) { + request.fields['id'] = id!; + request.fields['updated_by'] = userId!.toString(); + } else { + request.fields['created_by'] = userId!.toString(); + } + + print("USerDAta - $userData"); + + await attachFiles(request); + userData.forEach((key, value) { + if (key != 'policy_pdf_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + } else { + print('Something Missing..'); + } + }); + + print(" Sending request with fields: ${request.fields}"); + + showDialog( + context: context, + barrierDismissible: false, + builder: (_) => const CustomLoader( + message: 'Loading data...', + loaderColor: Colors.deepPurple, + useBlurBackground: true, + ), + ); + + 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) { + // Close the loader before showing any message + Navigator.of(context, rootNavigator: true).pop(); + // dispose(); + print("✅ PDF submitted successfully!"); + ToastHelper.showSuccessToast(context, 'PDF Uploaded'); + print("Response: ${response.body}"); + + final Map jsonResponse = jsonDecode(response.body); + final policy = + jsonResponse['data']?['file_read_data']?['value']?['policy']; + if (policy != null) { + final extractedData = { + 'id': jsonResponse['data']?['policy_id']?.toString(), + 'policy_number': policy['policy_number'], + 'issued_date': policy['issue_date'], + 'start_date': policy['period']?['start'], + 'end_date': policy['period']?['end'], + 'payment_mode': policy['payment_mode'] ?? 'online', + // optional if available + 'policy_pdf_file_name': + jsonResponse['data']?['policy_pdf_file_name'], + + // ✅ include premium details here + 'premium': + jsonResponse['data']?['file_read_data']?['value']?['premium'], + // optional if your API returns it + }; + + print('extractedData - $extractedData'); + updateUploadPDFPolicyData(extractedData); + } + } else if (response.statusCode == 403) { + await apiService.clearLocalStorageAndRedirect(); + } else { + print("❌ Submission failed. Status: ${response.statusCode}"); + print("Body: ${response.body}"); + + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(" Upload Policy Failed"), + content: Text( + "There was a problem in uploading pdf. Please try again.", + ), + actions: [ + TextButton( + child: Text("OK"), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + } catch (e) { + print("🔥 Error submitting user: $e"); + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + backgroundColor: Color(0xfff8fafc), + + content: Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + children: [ + // Expanded( + // child: + // Container( + // // color: Colors.white, + // padding: EdgeInsets.all(16.0), + // child: SingleChildScrollView( + // scrollDirection: Axis.vertical, + // child: Column( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [buildFormFields(context)], + // ), + // ), + // ), + buildFormFields(context), + SizedBox(height: 1), + ], + ), + ), + // ), + ), + ); + } + + Widget buildDocRC(BuildContext context, bool isMobile) { + return GestureDetector( + onTap: () { + // print("Upload $idget.id}{w"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=rc'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + "Download RC", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 15), + // isMobile ? const Spacer() : const SizedBox(width: 15), + const Icon( + Icons.file_download_outlined, + size: 16, + color: Colors.white, + ), + ], + ), + ), + ); + } + + Widget buildDocIdProof(BuildContext context, bool isMobile) { + return GestureDetector( + onTap: () { + print("Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=id_proof'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Download ID Proof", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 15), + // const SizedBox(width: 15), + Icon(Icons.file_download_outlined, size: 16, color: Colors.white), + ], + ), + ), + ); + } + + Widget buildDocPrevPolicy(BuildContext context, bool isMobile) { + return GestureDetector( + onTap: () { + print("Upload $selectedEnquiryId"); + final selectedId = selectedEnquiryId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + final path = + 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy'; + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Download Previous Policy", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 15), + // isMobile ? const Spacer() : const SizedBox(width: 15), + Icon(Icons.file_download_outlined, size: 16, color: Colors.white), + ], + ), + ), + ); + } + + Widget buildDocQuotation(BuildContext context, bool isMobile) { + return GestureDetector( + onTap: () { + print("Upload $selectedEnquiryId"); + final selectedId = acceptedQuotationId; + // final path = + // 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + // final path = + // 'api/enquiry/downloadEnquiryFile?enquiry_id=$selectedId&file_type=previous_policy'; + final path = + 'api/quotation/downloadAdditionalUploadedFile?id=$acceptedQuotationId'; + + apiService.getPdfDownload(path, selectedId); + }, + child: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: const Color(0xFF425B5B), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Proposal Documents", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, + ), + ), + ?isMobile ? null : SizedBox(width: 15), + // isMobile ? const Spacer() : const SizedBox(width: 15), + Icon(Icons.file_download_outlined, size: 16, color: Colors.white), + ], + ), + ), + ); + } + + Widget buildFormFields(BuildContext context) { + return Form( + key: _formKey, + child: Column( + children: [ + // if (docUploadedPDFFileUrlFromApi == null || + // docUploadedPDFFileUrlFromApi!.isEmpty) ...[ + // Text('No Data Found'), + // ], + + // Show form fields when URL is NOT null AND NOT empty + // if (docUploadedPDFFileUrlFromApi != null && + // docUploadedPDFFileUrlFromApi!.isNotEmpty) ...[ + + // if (selectedBrokerName != null) ...[ + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + // border: Border.all(color: const Colors.bla), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Basic Information', style: headingSTyles), + Divider(thickness: 0.1, color: Color(0xFF2E7D6E)), + Row( + children: [ + policynumber(context), + SizedBox(width: 20), + + Insuredname(context), + SizedBox(width: 20), + registerNumber(context), + SizedBox(width: 20), + buildPremiumAmount(context), + SizedBox(width: 20), + ], + ), + Row( + children: [ + Paymentmode(context), + SizedBox(width: 20), + buildInsurer(context), + SizedBox(width: 20), + buildAgentName(context), + SizedBox(width: 20), + buildBroker(context), + SizedBox(width: 20), + ], + ), + + Row( + children: [ + policyissuedate(context), + SizedBox(width: 20), + policystartdate(context), + SizedBox(width: 20), + policyenddate(context), + ], + ), + ], + ), + ), + SizedBox(height: 10), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + // border: Border.all(color: const Colors.bla), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Premium Breakdown', style: headingSTyles), + Divider(thickness: 0.1, color: Color(0xFF2E7D6E)), + + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildThirdParty(context), + buildOwnDamage(context), + buildPersonalAccident(context), + ], + ), + + SizedBox(width: 20), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildCGST(context), + buildSGST(context), + buildIGST(context), + buildPremiumTotal(context), + ], + ), + ], + ), + ), + SizedBox(height: 10), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + // border: Border.all(color: const Colors.bla), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Vehicle Details', style: headingSTyles), + Divider(thickness: 0.1, color: Color(0xFF2E7D6E)), + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildMake(context), + buildModel(context), + buildVehicleType(context), + buildFuelType(context), + ], + ), + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildEngineNo(context), + buildChassisNo(context), + buildCubicCapacity(context), + buildWeight(context), + ], + ), + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildYearOfManufacture(context), + buildDateOfRegistration(context), + ], + ), + ], + ), + ), + SizedBox(height: 10), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + // border: Border.all(color: const Colors.bla), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('RTO Details', style: headingSTyles), + Divider(thickness: 0.1, color: Color(0xFF2E7D6E)), + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildRTOStateCode(context), + buildRTOCityCode(context), + ], + ), + ], + ), + ), + SizedBox(height: 10), + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + // border: Border.all(color: const Colors.bla), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Commission Details', style: headingSTyles), + Divider(thickness: 0.1, color: Color(0xFF2E7D6E)), + Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildCommissonAmount(context), + buildCommissonAppliedRule(context), + ], + ), + ], + ), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () { + handleSave(); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 45.0, vertical: 8), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text( + // !hasPolicyData ? 'Submit' : 'Update', + 'Submit', + style: TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + // ], + ], + // ], + ), + ); + } + + Widget _buildResponsiveRow( + BuildContext context, + Widget first, + Widget second, + Widget third, + Widget fourth, + // Widget fifth, + // Widget Six, + ) { + if (ResponsiveLayout.isMobile(context)) { + // Stack vertically + return Column(children: [first, const SizedBox(height: 2), second]); + } else { + // Place side by side + return Row( + children: [ + Expanded(child: first), + const SizedBox(width: 20), + Expanded(child: second), + const SizedBox(width: 20), + Expanded(child: third), + const SizedBox(width: 20), + Expanded(child: fourth), + // const SizedBox(width: 20), + // Expanded(child: fifth), + // const SizedBox(width: 20), + // Expanded(child: Six), + ], + ); + } + } + + Widget registerNumber(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Vehicle Number*', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['regNum']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + // validator: (value) => Validators.phone(value, "phNumber"), + readOnly: true, + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildInsurer(BuildContext context, {fromHeader = true}) { + Map? selectedInsurerd = filteredInsurersData.firstWhere( + (item) => item['id'].toString() == selectedInsurer, + orElse: () => {}, + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Insurer *', style: _textStyle), + + SizedBox(height: 5), + Container( + height: 30, + width: MediaQuery.of(context).size.width * 0.12, + child: DropdownSearch>( + key: dropDownKeyInsurerEnqAsgn, + selectedItem: selectedInsurerd.isNotEmpty ? selectedInsurerd : null, + // items: (filter, infiniteScrollProps) { + // return filteredInsurersData; + // }, + // 👇 Enable async filtering based on user input + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredInsurersData; + } + return filteredInsurersData.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null ? selectedItem['name'].toString() : "", + style: GoogleFonts.poppins(fontSize: 11, color: Colors.black), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Insurer", + ).copyWith( + filled: true, + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + searchDelay: Duration(milliseconds: 200), + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Search Insurer...", + hintStyle: GoogleFonts.inter( + fontSize: 11, + color: Colors.black, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Text( + item['name'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + // constraints: BoxConstraints(), + ), + + onChanged: (val) { + if (val != null) { + print("Selected Insurer : ${val['name']}"); + print("Id: ${val['id']}"); + selectedInsurer = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget buildIdv(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('IDV *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['idv']!, + readOnly: true, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ], + ); + } + + Widget buildPremiumAmount(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Premium Amount *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['premium_amount']!, + readOnly: true, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => + Validators.doubleNumber(value, "Premium Amount"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildPlanType(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Plan Type *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['planType']!, + readOnly: true, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ], + ); + } + + Widget Insuredname(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Insured Name *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['policyInsName']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => + Validators.requiredField(value, "policyInsName"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + // + // Widget premiumamount(BuildContext context) { + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Text('Premium Amount ', style: _textStyle), + // SizedBox(height: 10), + // ThemedFormField( + // controller: controllers['premium_amount']!, + // // validator: (value) => + // // Validators.requiredField(value, "policyPremiumAmount"), + // txtwidth: ResponsiveLayout.isMobile(context) + // ? null + // : MediaQuery.of(context).size.width * 0.26, + // ), + // ], + // ); + // } + + Widget policynumber(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Policy Number ', style: _textStyle), + SizedBox(height: 5), + ThemedFormField( + controller: controllers['policyNumber']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + // validator: (value) => Validators.requiredField(value, "policyNumber"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z 0-9]')), + ], + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildBroker(BuildContext context) { + Map? selectedBrokers = filteredBrokerData.firstWhere( + (item) => item['id'].toString() == selectedBroker, + orElse: () => {}, + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Broker *', style: _textStyle), + SizedBox(width: 10), + // SizedBox( + // width: MediaQuery.of(context).size.width * 0.095, + // child: Text( + // '$selectedBrokerName', + // style: GoogleFonts.inter(fontSize: 12), + // ), + // ), + SizedBox( + height: 30, + width: MediaQuery.of(context).size.width * 0.12, + child: DropdownSearch>( + key: dropDownKeyBroker, + selectedItem: selectedBrokers.isNotEmpty ? selectedBrokers : null, + items: (filter, infiniteScrollProps) { + return filteredBrokerData; + }, + + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null ? selectedItem['name'].toString() : "", + style: GoogleFonts.poppins(fontSize: 11, color: Colors.black), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Broker", + ).copyWith( + filled: true, + // errorStyle: const TextStyle( + // fontSize: 9, + // + // // height: 0.0 + // ), + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + filled: true, + fillColor: Colors.white, + hintText: "Search Broker...", + hintStyle: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Text( + item['name'].toString(), + style: GoogleFonts.inter(fontSize: 12, color: Colors.black), + ), + ); + }, + // constraints: BoxConstraints(), + ), + + onChanged: (val) { + if (val != null) { + print("Selected Broker : ${val['name']}"); + print("Id: ${val['id']}"); + selectedBroker = val['id']; + setState(() { + selectedBrokerName = val['name']; + print('selectedBrokerName - $selectedBrokerName'); + }); + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget buildAgentName(BuildContext context, {fromHeader = true}) { + Map? selectedAgntName = filteredAgentData.firstWhere( + (item) => item['id'].toString() == selectedAgent, + orElse: () => {}, + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Partner *', style: _textStyle), + + SizedBox(height: 5), + SizedBox( + width: MediaQuery.of(context).size.width * 0.12, + // width: fromHeader + // ? MediaQuery.of(context).size.width * 0.11 + // : MediaQuery.of(context).size.width * 0.08, + height: 30, + child: DropdownSearch>( + key: dropDownKeyAgent, + selectedItem: selectedAgntName.isNotEmpty ? selectedAgntName : null, + // items: (filter, infiniteScrollProps) { + // return filteredAgentData; + // }, + items: (filter, infiniteScrollProps) async { + if (filter.isEmpty) { + return filteredAgentData; + } + return filteredAgentData.where((item) { + return item['name'].toString().toLowerCase().contains( + filter.toLowerCase(), + ); + }).toList(); + }, + + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + validator: (val) { + if (val == null) { + return "Required"; // ✅ error message + } + return null; + }, + suffixProps: DropdownSuffixProps( + // make sure the dropdown button is visible + dropdownButtonProps: DropdownButtonProps( + isVisible: true, + padding: EdgeInsets.zero, // remove default padding + constraints: const BoxConstraints( + // shrink icon tap area + minWidth: 12, + minHeight: 12, + ), + iconSize: 15, // smaller icon + // icon: const Icon(Icons.arrow_drop_down), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem != null + ? selectedItem['name'].toString() + : "", // ✅ FIXED + style: GoogleFonts.poppins(fontSize: 11, color: Colors.black), + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + ), + ), + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Partner Name", + ).copyWith( + filled: true, + // errorStyle: const TextStyle( + // fontSize: 9, + // + // // height: 0.0 + // ), + fillColor: + Colors.white, // 👈 makes the dropdown input white + isDense: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide( + color: Color(0xFFE2E8F0), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 6, + ), + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + + searchFieldProps: TextFieldProps( + autofocus: true, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(1), + filled: true, + fillColor: Colors.white, + hintText: "Partner Name", + hintStyle: GoogleFonts.inter( + fontSize: 10, + color: Colors.grey, + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + + // constraints: BoxConstraints(), + itemBuilder: (context, item, isDisabled, isSelected) { + return Container( + // color: isSelected ? Colors.blue.withOpacity(0.1) : null, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + item['name'].toString(), + style: GoogleFonts.inter( + fontSize: 12, + color: Colors.black, + ), + ), + Text( + item['agent_code'].toString(), + style: GoogleFonts.inter( + fontSize: 11, + color: Colors.grey, + ), + ), + ], + ), + ); + }, + ), + + onChanged: (val) { + if (val != null) { + print("Selected Partner : ${val['name']}"); + print("Id: ${val['id']}"); + selectedAgent = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ], + ); + } + + Widget Paymentmode(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Payment Mode *', style: _textStyle), + SizedBox(width: 15), + // SizedBox( + // width: MediaQuery.of(context).size.width * 0.075, + // child: Text( + // selectedPaymentMode, + // // controllers['policyPaymentMode']!.text, + // style: GoogleFonts.inter(fontSize: 12), + // ), + // ), + ThemedFormField( + controller: controllers['policyPaymentMode']!, + + // borderColor: Colors.white, + // highlightColor: Colors.white, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + errorBorderColor: Color(0xffEDF6F5), + hintText: 'Online / Cash', + // borderColor: Color(0xffEDF6F5), + readOnly: true, + validator: (value) => + Validators.requiredField(value, "policyPaymentMode"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget policyissuedate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Issue Date', style: _textStyle), + SizedBox(height: 10), + ThemedDateField( + hintText: "Select Date", + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + // backgroundColor: const Color(0xFFECECEC), + // validator: (value) => Validators.requiredField(value, "date"), + controller: controllers['issueDate']!, + onDateSelected: (date) { + print("Picked Date: $date"); + + controllers['issueDate']?.text = DateFormat( + 'dd-MM-yyyy', + ).format(date); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + Widget policystartdate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Start Date', style: _textStyle), + SizedBox(height: 10), + ThemedDateField( + hintText: "Select Date", + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + // backgroundColor: const Color(0xFFECECEC), + // validator: (value) => Validators.requiredField(value, "date"), + controller: controllers['startDate']!, + onDateSelected: (date) { + print("Picked Date: $date"); + + controllers['startDate']?.text = DateFormat( + 'dd-MM-yyyy', + ).format(date); + + // auto set end date (1 year later - 1 day if needed) + final endDate = DateTime( + date.year + 1, + date.month, + date.day, + ).subtract(const Duration(days: 1)); // optional: subtract 1 day + + controllers['endDate']?.text = DateFormat( + 'dd-MM-yyyy', + ).format(endDate); + + print("Auto-set End Date: $endDate"); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + Widget policyenddate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('End Date', style: _textStyle), + SizedBox(height: 10), + ThemedDateField( + hintText: "Select Date", + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + // backgroundColor: const Color(0xFFECECEC), + // validator: (value) => Validators.requiredField(value, "date"), + validator: (value) { + // if (value == null || value.isEmpty) { + // return "Required"; + // } + + final startDateControllerText = controllers['startDate']?.text; + if (startDateControllerText == null || + startDateControllerText.isEmpty) { + return "Select start date first"; + } + + final startDate = DateFormat( + 'dd-MM-yyyy', + ).parse(startDateControllerText); + final endDate = DateFormat('dd-MM-yyyy').parse(value!); + + if (endDate.isBefore(startDate)) { + return "End date cannot be before start date"; + } + + // Minimum end date = start date + 1 year - 1 day (or just +1 year) + final minEndDate = DateTime( + startDate.year + 1, + startDate.month, + startDate.day, + ).subtract(const Duration(days: 1)); + + if (endDate.isBefore(minEndDate)) { + return "End date must be at least 1 year from start date"; + } + + return null; + + // final startDateControllerText = controllers['startDate']?.text; + // if (startDateControllerText == null || + // startDateControllerText.isEmpty) { + // return "Select start date first"; + // } + // + // final startDate = DateFormat( + // 'dd-MM-yyyy', + // ).parse(startDateControllerText); + // final endDate = DateFormat('dd-MM-yyyy').parse(value); + // + // if (endDate.isBefore(startDate)) { + // return "End date cannot be before start date"; + // } + // + // final expectedEndDate = DateTime( + // startDate.year + 1, + // startDate.month, + // startDate.day, + // ).subtract(const Duration(days: 1)); + // + // if (endDate != expectedEndDate) { + // return "End date must be exactly 1 year from start date"; + // } + // + // return null; // valid + }, + controller: controllers['endDate']!, + onDateSelected: (date) { + print("Picked Date: $date"); + + controllers['endDate']?.text = DateFormat( + 'dd-MM-yyyy', + ).format(date); + _formKey.currentState?.validate(); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + Widget buildUploadPolicyPdf(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('Upload Policy PDF * ', style: _textStyle), + ), + // const SizedBox(height: 10), + // SizedBox(width: 20), + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ThemedUploadField( + hintText: selectedPDFFileNames ?? "Upload Document", + allowedExtensions: ['pdf'], + // backgroundColor: Colors.white, + backgroundColor: Color(0xffEDF6F5), + txtheight: 35, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : (docUploadedPDFFileUrlFromApi != null) + ? MediaQuery.of(context).size.width * 0.117 + // ? MediaQuery.of(context).size.width * 0.135 + // ? MediaQuery.of(context).size.width * 0.12 + : MediaQuery.of(context).size.width * 0.14, + // : MediaQuery.of(context).size.width * 0.15, + // backgroundColor: Color(0xFFEDF6F5), + onFileSelected: (fileName, file) async { + print("Picked file: $fileName (${file.size} bytes)"); + + if (!fileName.toLowerCase().endsWith('.pdf')) { + ToastHelper.showErrorToast( + context, + 'Only PDF files are allowed.', + ); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Only PDF files are allowed.'), + backgroundColor: Colors.red, + ), + ); + return; // Stop here + } + + print("Picked file: $fileName (${file.size} bytes)"); + setState(() { + docPDFUploadedFile = file; + }); + + // if (selectedBrokerName == 'Nhance') { + // handleUploadPolicy(); + // } + }, + ), + + if (docUploadedPDFFileUrlFromApi != null) ...[ + const SizedBox(width: 5), + Tooltip( + message: 'Download', + // color: Colors.white, + child: + // Row( + // mainAxisSize: MainAxisSize.min, + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + InkWell( + onTap: () => apiService.downloadFile( + apiUrl: + 'api/policy/downloadPolicyFile?policy_id=$choosedPolcyId&file_type=policy_pdf', + apiId: choosedPolcyId, + localFile: docPDFUploadedFile, + fileName: selectedPDFFileNames, + ), + + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 5, + vertical: 8, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: Color(0xFF425B5B), + // color: Colors.green.shade300, + ), + child: Row( + children: const [ + // Text( + // "Download", + // style: TextStyle( + // fontSize: 12, + // fontWeight: FontWeight.w200, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 5), + Icon(Icons.download, size: 13, color: Colors.white), + ], + ), + ), + ), + // ], + // ), + ), + ], + ], + ), + ], + ); + } + + Widget buildUploadPolicyReceipt(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Upload Policy Receipt *', style: _textStyle), + const SizedBox(height: 10), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ThemedUploadField( + hintText: selectedFileNames ?? "Upload Document", + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + // backgroundColor: Color(0xFFEDF6F5), + onFileSelected: (fileName, file) { + print("Picked file: $fileName (${file.size} bytes)"); + setState(() { + docUploadedFile = file; + }); + }, + ), + const SizedBox(height: 5), + + if (docUploadedFileUrlFromApi != null) + Container( + // color: Colors.white, + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () => apiService.downloadFile( + apiUrl: + 'api/policy/downloadPolicyFile?policy_id=$choosedPolcyId&file_type=policy_payment_receipt', + apiId: choosedPolcyId, + localFile: docUploadedFile, + fileName: selectedFileNames, + ), + child: Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: Color(0xFF425B5B), + // color: Colors.green.shade300, + ), + child: Row( + children: const [ + Text( + "Download", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w200, + color: Colors.white, + ), + ), + SizedBox(width: 5), + Icon(Icons.download, size: 13, color: Colors.white), + ], + ), + ), + ), + ], + ), + ), + ], + ), + ], + ); + } + + Widget buildResponsiveUploadField({ + String? label, // 🔹 make optional + required String? hintText, + required void Function(String fileName, dynamic file) onFileSelected, + }) { + final isMobile = ResponsiveLayout.isMobile(context); + + final uploadWidget = ThemedUploadField( + hintText: hintText ?? "Upload Documents", + txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26, + onFileSelected: onFileSelected, + ); + + if (isMobile) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (label != null && label.isNotEmpty) ...[ + // ✅ only render if label is given + Text(label, style: _textStyle), + const SizedBox(height: 8), + ], + uploadWidget, + const SizedBox(height: 16), + ], + ); + } else { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (label != null && label.isNotEmpty) ...[ + Expanded(child: Text(label, style: _textStyle)), + const SizedBox(width: 10), + ], + uploadWidget, + ], + ); + } + } + + // NEW FIELDs + + Widget buildThirdParty(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.12, + child: Text('Third Party', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['tp']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + // validator: (value) => Validators.requiredField(value, "Third Party"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + // onChanged: (value) => calculateAmount(), + onChanged: (v) { + print('pa onChanged -> $v'); // should show on every keystroke + calculateAmount(); + }, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildOwnDamage(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('Own Damage ', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['od']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + // validator: (value) => Validators.requiredField(value, "OwnDamage"), + onChanged: (value) => calculateAmount(), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildPersonalAccident(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('Personal Accident', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['pa']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + onChanged: (value) => calculateAmount(), + // validator: (value) => + // Validators.requiredField(value, "PersonalAccident"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildCGST(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('CGST', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['cgst']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + validator: (value) => Validators.requiredField(value, "CGST"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildSGST(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('SGST', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['sgst']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + validator: (value) => Validators.requiredField(value, "SGST"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildIGST(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('IGST', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['igst']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + validator: (value) => Validators.requiredField(value, "IGST"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildPremiumTotal(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: Text('Total Premium *', style: _textStyle), + ), + SizedBox(width: 20), + ThemedFormField( + controller: controllers['premiumTOT']!, + // backgroundColor: Color(0xffEDF6F5), + errorBorderColor: Color(0xffEDF6F5), + hintText: '0', + validator: (value) => Validators.requiredField(value, "premium"), + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'[.0-9]')), + ], + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.14, + ), + ], + ); + } + + Widget buildRTOStateCode(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('RTO State Code *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['rto_state_code']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => + Validators.requiredField(value, "RTO State Code"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildRTOCityCode(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('RTO City Code *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['rto_city_code']!, + validator: (value) => + Validators.requiredField(value, "RTO City Code"), + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildCommissonAmount(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Commission Amount', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['commison_amount']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + // validator: (value) => + // Validators.requiredField(value, "RTO City Code"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildCommissonAppliedRule(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Commission Applied Rule', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['commison_applied_rule']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + // validator: (value) => + // Validators.requiredField(value, "RTO City Code"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildWeight(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Weight *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['weight']!, + validator: (value) => Validators.requiredField(value, "weight"), + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildFuelType(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Fuel Type *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['fuel_type']!, + validator: (value) => Validators.requiredField(value, "Fuel Type"), + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildDateOfRegistration(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Date Of Registration *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['date_of_registration']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => + Validators.requiredField(value, "Date Of Registration"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildYearOfManufacture(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Year Of Manufacture *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['year_of_manufacture']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => + Validators.requiredField(value, "Year Of Manufacture"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildEngineNo(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Engine No *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['engine_no']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => Validators.requiredField(value, "Engine No"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildChassisNo(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Chassis No *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['chassis_no']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => Validators.requiredField(value, "Chassis No"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildMake(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Make *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['make']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => Validators.requiredField(value, "Make"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildModel(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Model *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['model']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => Validators.requiredField(value, "Model"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildCubicCapacity(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Cubic Capacity *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['cubic_capacity']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => + Validators.requiredField(value, "Cubic Capacity"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildVehicleType(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Vehicle Type *', style: _textStyle), + SizedBox(height: 10), + ThemedFormField( + controller: controllers['vehicle_type']!, + borderColor: Color(0xFFE2E8F0), + highlightColor: Color(0xFF50A398), + validator: (value) => Validators.requiredField(value, "Vehicle Type"), + txtheight: 30, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.12, + ), + ], + ); + } + + Widget buildResponsiveField({required String label, required Widget field}) { + final isMobile = ResponsiveLayout.isMobile(context); + + if (isMobile) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: _textStyle), + const SizedBox(height: 8), + field, + const SizedBox(height: 16), + ], + ); + } else { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(child: Text(label, style: _textStyle)), + const SizedBox(width: 10), + field, + ], + ); + } + } + + static final _textStyle = GoogleFonts.inter( + fontSize: 11, + color: Color(0XFF334155), + fontWeight: FontWeight.w500, + ); + + static final headingSTyles = GoogleFonts.inter( + fontSize: 12.5, + // color: Color(0XFF334155), + color: Color(0xFF2E7D6E), + fontWeight: FontWeight.w600, + ); + static const _textStrongStyle = TextStyle( + fontSize: 12, + fontWeight: FontWeight.w800, + ); +} diff --git a/lib/presentation/themes/indicators/side_Drawer_Panel.dart b/lib/presentation/themes/indicators/side_Drawer_Panel.dart index ed26658..e5e0005 100644 --- a/lib/presentation/themes/indicators/side_Drawer_Panel.dart +++ b/lib/presentation/themes/indicators/side_Drawer_Panel.dart @@ -52,7 +52,7 @@ class SideDrawerPanel extends StatelessWidget { children: [ if (title != null) Text( - 'Proposal Creation', + title!, style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w600, diff --git a/lib/presentation/themes/indicators/text_field_theme_inline_editor.dart b/lib/presentation/themes/indicators/text_field_theme_inline_editor.dart index d263b5b..e3d1aac 100644 --- a/lib/presentation/themes/indicators/text_field_theme_inline_editor.dart +++ b/lib/presentation/themes/indicators/text_field_theme_inline_editor.dart @@ -31,6 +31,8 @@ class ThemedFormInlineField extends HookWidget { this.onChanged, this.isdense, this.padVertical, + this.errFieldFont, + this.errFieldHgt, }); final String? hintText; @@ -47,6 +49,8 @@ class ThemedFormInlineField extends HookWidget { final Color? highlightColor; final Color? textColr; final double? txtwidth; + final double? errFieldFont; + final double? errFieldHgt; final bool readOnly; final bool? isdense; final bool? isShowCursor; @@ -84,7 +88,16 @@ class ThemedFormInlineField extends HookWidget { ); final inputDecoration = InputDecoration( isDense: isdense ?? false, - errorStyle: TextStyle(color: Color(0xFFD83731)), + // errorStyle: const TextStyle( + // fontSize: 9, + // + // // height: 0.0 + // ), + errorStyle: TextStyle( + color: Color(0xFFD83731), + fontSize: errFieldFont ?? 12, + height: errFieldHgt ?? 10, + ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(