From e2c02c4e122d28828cbb27397152eb7421a70d9c Mon Sep 17 00:00:00 2001 From: venbaittech Date: Fri, 12 Sep 2025 16:15:43 +0530 Subject: [PATCH] UI_FILE_UPLOAD_CHNGS UI_ENQUIRY --- .flutter-plugins-dependencies | 2 +- lib/core/routing/app_router.dart | 15 +- lib/core/routing/routes.dart | 2 + lib/core/services/api_service.dart | 405 ++++++---- lib/data/utils/Pagination.dart | 2 +- lib/main.dart | 28 +- lib/presentation/layouts/main_layout.dart | 6 +- .../screens/Enquiry/enquiry/enquiry_tab.dart | 729 +++++++++++++++++ .../screens/Enquiry/enquiry/policy_tab.dart | 436 ++++++++++ .../Enquiry/enquiry/quotation_tab.dart | 745 +++++++++++++++++ .../screens/Enquiry/enquiry/tabs.dart | 127 +++ .../screens/Enquiry/enquiryList.dart | 453 ++++++++--- .../screens/UserManagement/Agent/agent.dart | 336 +++++--- .../Agent/agentIncentiveFile.dart | 101 ++- .../UserManagement/Agent/agentList.dart | 104 ++- .../Profile/profile_mobile.dart | 749 ++++++++++++++++++ .../UserManagement/Profile/profile_web.dart | 459 ++++++----- .../screens/UserManagement/Staff/staff.dart | 5 +- .../UserManagement/Staff/staffList.dart | 79 +- .../indicators/customizd_file_upload.dart | 215 +++++ .../themes/indicators/export_btn.dart | 23 +- .../themes/indicators/fileUploadService.dart | 40 + .../themes/indicators/outlineWidget | 147 ++++ .../themes/indicators/singleFileUpload.dart | 70 ++ .../themes/indicators/upload_doc_theme.dart | 361 +++++---- lib/presentation/widgets/drawer_menu.dart | 6 +- lib/presentation/widgets/mobile_tabs.dart | 7 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 16 + pubspec.yaml | 1 + 30 files changed, 4808 insertions(+), 863 deletions(-) create mode 100644 lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart create mode 100644 lib/presentation/screens/Enquiry/enquiry/policy_tab.dart create mode 100644 lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart create mode 100644 lib/presentation/screens/Enquiry/enquiry/tabs.dart create mode 100644 lib/presentation/screens/UserManagement/Profile/profile_mobile.dart create mode 100644 lib/presentation/themes/indicators/customizd_file_upload.dart create mode 100644 lib/presentation/themes/indicators/fileUploadService.dart create mode 100644 lib/presentation/themes/indicators/outlineWidget create mode 100644 lib/presentation/themes/indicators/singleFileUpload.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 00219e0..b162cf5 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":"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":"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.1/","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":"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":"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.17/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.18/","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":"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.1/","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":"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":"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":"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":"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":"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":"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-09-09 18:03:44.297394","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.2/","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":"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.1/","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.2/","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":"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.17/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.18/","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.2/","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.1/","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.2/","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.2/","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.2/","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":"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":"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-09-12 14:46:54.962836","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 bf8759a..1f58845 100644 --- a/lib/core/routing/app_router.dart +++ b/lib/core/routing/app_router.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:nhance_partner/core/routing/routes.dart'; +import 'package:nhance_partner/presentation/screens/Enquiry/enquiryList.dart'; import 'package:nhance_partner/presentation/screens/UserManagement/Profile/profile_web.dart'; import 'package:nhance_partner/presentation/screens/claims/claimsList.dart'; import 'package:nhance_partner/presentation/screens/dashboard/dashboard.dart'; import '../../data/services/auth_service.dart'; +import '../../presentation/screens/Enquiry/enquiry/tabs.dart'; import '../../presentation/screens/UserManagement/Agent/agent.dart'; import '../../presentation/screens/UserManagement/Agent/agentList.dart'; +import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart'; import '../../presentation/screens/UserManagement/Staff/staff.dart'; import '../../presentation/screens/UserManagement/Staff/staffList.dart'; import '../../presentation/screens/home/home_screen.dart'; @@ -35,7 +38,7 @@ final GoRouter appRouter = GoRouter( GoRoute( path: AppRoutes.profile, - builder: (context, state) => const ProfilePopUp(), + builder: (context, state) => const Profile(), ), GoRoute( @@ -76,6 +79,16 @@ final GoRouter appRouter = GoRouter( } }, ), + + GoRoute( + path: AppRoutes.enquiryLst, + builder: (context, state) => const EnquiryList(), + ), + + GoRoute( + path: AppRoutes.tabEnquiry, + builder: (context, state) => const TabEnquiryList(), + ), ], redirect: (context, state) async { final loggedIn = await AuthService.isLoggedIn(); diff --git a/lib/core/routing/routes.dart b/lib/core/routing/routes.dart index df656be..21a0f0f 100644 --- a/lib/core/routing/routes.dart +++ b/lib/core/routing/routes.dart @@ -8,4 +8,6 @@ class AppRoutes { static const agent = '/agent/:id'; static const String staffLst = '/staffLst'; static const staff = '/staff/:id'; + static const String enquiryLst = '/enquiryLst'; + static const String tabEnquiry = '/tabEnquiry'; } diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 1380849..db06e6b 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -1,3 +1,5 @@ +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:nhance_partner/data/services/auth_service.dart'; @@ -76,147 +78,7 @@ class ApiService { ); return _handleResponse(response); } - - Future> fetchAgentIncentiveList(agentId) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - - final url = Uri.parse( - '${Env.apiUrl}agent/agentIncentiveFileList?agent_id=${agentId}', - ); - - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/agent/agentIncentiveFileList?agent_id=${agentId}', - // ); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } - - Future> fetchManagerIncentiveList(mangerId) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - - final url = Uri.parse( - '${Env.apiUrl}staff/managerIncentiveFileList?manager_id=$mangerId', - ); - - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/agent/agentIncentiveFileList?agent_id=${agentId}', - // ); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } - - Future> fetchAgentUserList(int managerId) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - - final userId = '1'; - final url = Uri.parse( - '${Env.apiUrl}agent/agentList?manager_id=${managerId}', - ); - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/agent/agentList?manager_id=${managerId}', - // ); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } - - Future> findSingleAgentData(id) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - // final url = Uri.parse('${Env.apiUrl}/api/agent/agentList'); - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/agent/findAgent?id=$id', - // ); - - final url = Uri.parse('${Env.apiUrl}agent/findAgent?id=$id'); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } - - Future> deleteAgentIncentiveFile(id) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - // final url = Uri.parse('${Env.apiUrl}/api/agent/agentList'); - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/agent/deleteAgentIncentiveFile?id=$id', - // ); - - final url = Uri.parse('${Env.apiUrl}agent/deleteAgentIncentiveFile?id=$id'); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } - - Future> fetchStaffUserList(int managerId) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/staff/staffList?manager_id=${managerId}', - // ); - - final url = Uri.parse( - '${Env.apiUrl}staff/staffList?manager_id=${managerId}', - ); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } - - Future> findSingleStaffData(id) async { - // print(_token); - if (_token == null) { - await _initializeToken(); - } - // final url = Uri.parse('${Env.apiUrl}/api/staff/findStaff?id=$id'); - // final url = Uri.parse( - // 'https://venbait.in/nhance/partner/dev/api/staff/findStaff?id=$id', - // ); - - final url = Uri.parse('${Env.apiUrl}staff/findStaff?id=$id'); - final headers = { - 'Authorization': 'Bearer $_token' ?? '', - 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', - }; - final response = await _makeGetRequest(url, headers); - return response; - } + // --------------------------- COMMON FILES __________________________________________ Future> _handleResponse(http.Response response) async { if (response.statusCode == 200) { @@ -290,6 +152,39 @@ class ApiService { } } + Future downloadFile({ + required String? apiUrl, + required PlatformFile? localFile, + required String? fileName, + String? apiId, // optional if your API needs it + }) async { + try { + if (localFile != null) { + if (kIsWeb) { + final blob = html.Blob([localFile.bytes!]); + final url = html.Url.createObjectUrlFromBlob(blob); + + final anchor = html.AnchorElement(href: url) + ..setAttribute('download', localFile.name) + ..click(); + + html.Url.revokeObjectUrl(url); + print("Download triggered successfully (web)!"); + } else { + print("Local file path: ${localFile.path}"); + // await OpenFilex.open(localFile.path!); + } + } else if (apiUrl != null) { + print("Download from API: $apiUrl"); + await getPdfDownload(apiUrl, apiId); + } else { + print("⚠️ No file available to download"); + } + } catch (e) { + print("Error during download: $e"); + } + } + Future> updateStatus(id, status, role) async { final Map data = { "id": int.parse(id), @@ -324,4 +219,232 @@ class ApiService { final response = await _makePostRequestJson(url, data, headers); return response; } + + // -------------------------------- AGENT ---------------------------------------------- + + Future> fetchAgentIncentiveList(agentId) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + final url = Uri.parse( + '${Env.apiUrl}agent/agentIncentiveFileList?agent_id=${agentId}', + ); + + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/agent/agentIncentiveFileList?agent_id=${agentId}', + // ); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + Future> fetchManagerIncentiveList(mangerId) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + final url = Uri.parse( + '${Env.apiUrl}staff/managerIncentiveFileList?manager_id=$mangerId', + ); + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + Future> fetchAgentUserList(int managerId) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + final userId = '1'; + final url = Uri.parse( + '${Env.apiUrl}agent/agentList?manager_id=${managerId}', + ); + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + Future> findSingleAgentData(id) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + // final url = Uri.parse('${Env.apiUrl}/api/agent/agentList'); + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/agent/findAgent?id=$id', + // ); + + final url = Uri.parse('${Env.apiUrl}agent/findAgent?id=$id'); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + Future> deleteAgentIncentiveFile(id) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + // final url = Uri.parse('${Env.apiUrl}/api/agent/agentList'); + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/agent/deleteAgentIncentiveFile?id=$id', + // ); + + final url = Uri.parse('${Env.apiUrl}agent/deleteAgentIncentiveFile?id=$id'); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + // ------------------------------------ STAFF ----------------------------------------------------- + + Future> fetchStaffUserList(int managerId) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/staff/staffList?manager_id=${managerId}', + // ); + + final url = Uri.parse( + '${Env.apiUrl}staff/staffList?manager_id=${managerId}', + ); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + Future> findSingleStaffData(id) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + // final url = Uri.parse('${Env.apiUrl}/api/staff/findStaff?id=$id'); + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/staff/findStaff?id=$id', + // ); + + final url = Uri.parse('${Env.apiUrl}staff/findStaff?id=$id'); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + // ----------------------------------- ENQUIRY ------------------------------------------------- + + Future> fetchEnquiryList(int id, role) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + final userId = '1'; + final url; + + if (role == 'manager') { + url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?manager_id=$id'); + } else if (role == 'staff') { + url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?staff_id=$id'); + } else { + url = Uri.parse('${Env.apiUrl}enquiry/enquiryList?agent_id=$id'); + } + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/agent/agentList?manager_id=${managerId}', + // ); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + //------------------------------------ Quotation ------------------------------------------------ + + Future> fetchQuotationList(int managerId) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + // final url = Uri.parse( + // 'https://venbait.in/nhance/partner/dev/api/staff/staffList?manager_id=${managerId}', + // ); + + final url = Uri.parse( + '${Env.apiUrl}quotation/quotationList?manager_id=${managerId}', + ); + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } + + // --------------------------------- MASTER DATA ---------------------------------------------- + + Future> fetchMasterDropDown(String val) async { + // print(_token); + if (_token == null) { + await _initializeToken(); + } + + print('VAl - $val'); + + dynamic url; + + if (val == 'staffRole') { + url = Uri.parse('${Env.apiUrl}master/getRoleMaster'); + } else if (val == 'vehicleType') { + url = Uri.parse('${Env.apiUrl}master/getVehicleTypeMaster'); + } else if (val == 'InsuranceType') { + url = Uri.parse('${Env.apiUrl}master/getInsurancePlanTypeMaster'); + } else if (val == 'Insurers') { + url = Uri.parse('${Env.apiUrl}master/getInsurersMaster'); + } else if (val == 'Staffs') { + url = Uri.parse('${Env.apiUrl}master/getStaffMaster'); + } else if (val == 'Claim') { + url = Uri.parse('${Env.apiUrl}master/getClaimMaster'); + } else if (val == 'Endorsement') { + url = Uri.parse('${Env.apiUrl}master/getEndorsementMaster'); + } + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + final response = await _makeGetRequest(url, headers); + return response; + } } diff --git a/lib/data/utils/Pagination.dart b/lib/data/utils/Pagination.dart index 9ed07bf..bdcaf63 100644 --- a/lib/data/utils/Pagination.dart +++ b/lib/data/utils/Pagination.dart @@ -254,4 +254,4 @@ class PaginationControls extends StatelessWidget { child: Text('...', style: TextStyle(fontSize: 16)), ); } -} \ No newline at end of file +} diff --git a/lib/main.dart b/lib/main.dart index 1f62fd2..1bbecd8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:nhance_partner/presentation/providers/manager_provider.dart'; import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -31,13 +32,15 @@ Future main() async { // prefs.clear(); if (kIsWeb) { await Firebase.initializeApp( - options: const FirebaseOptions( - apiKey: "AIzaSyC4yHbCX4mQu0jO81pJrDwxKLQlTQWofrc", - authDomain: "nhance-ee8d1.firebaseapp.com", - projectId: "nhance-ee8d1", - storageBucket: "nhance-ee8d1.firebasestorage.app", - messagingSenderId: "1084115316849", - appId: "1:1084115316849:web:8fc3b1c886349ae86c6bd0")); + options: const FirebaseOptions( + apiKey: "AIzaSyC4yHbCX4mQu0jO81pJrDwxKLQlTQWofrc", + authDomain: "nhance-ee8d1.firebaseapp.com", + projectId: "nhance-ee8d1", + storageBucket: "nhance-ee8d1.firebasestorage.app", + messagingSenderId: "1084115316849", + appId: "1:1084115316849:web:8fc3b1c886349ae86c6bd0", + ), + ); } else { await Firebase.initializeApp(); await FirebaseAppCheck.instance.activate( @@ -77,7 +80,6 @@ class MyApp extends ConsumerStatefulWidget { } class _MyAppState extends ConsumerState { - @override void initState() { super.initState(); @@ -91,10 +93,14 @@ class _MyAppState extends ConsumerState { Widget build(BuildContext context) { return MaterialApp.router( debugShowCheckedModeBanner: false, - title: 'Clean Architecture App', - theme: ThemeData(primarySwatch: Colors.blue), + title: 'Nhance Partner', + theme: ThemeData( + primarySwatch: Colors.blue, + textTheme: GoogleFonts.interTextTheme( + Theme.of(context).textTheme, // base on default styles + ), + ), routerConfig: appRouter, ); } } - diff --git a/lib/presentation/layouts/main_layout.dart b/lib/presentation/layouts/main_layout.dart index 068ace0..fad7f95 100644 --- a/lib/presentation/layouts/main_layout.dart +++ b/lib/presentation/layouts/main_layout.dart @@ -37,8 +37,12 @@ class MainLayout extends StatelessWidget { bottomNavigationBar: MobileTabs( onTabChanged: (index) { debugPrint("Mobile tab changed to $index"); - if (index == 1) { + if (index == 0) { + context.go(AppRoutes.dashboard); + } else if (index == 1) { context.go(AppRoutes.profile); + } else if (index == 2) { + context.go(AppRoutes.tabEnquiry); } }, ), diff --git a/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart b/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart new file mode 100644 index 0000000..044c9ed --- /dev/null +++ b/lib/presentation/screens/Enquiry/enquiry/enquiry_tab.dart @@ -0,0 +1,729 @@ +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:nhance_partner/presentation/layouts/responsive_layout.dart'; +import 'package:universal_html/html.dart' as html; + +import '../../../../core/services/api_service.dart'; +import '../../../../data/services/auth_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../../data/utils/validators.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../providers/manager_provider.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/text_field_theme.dart'; +import '../../../themes/indicators/upload_doc_theme.dart' + hide ThemedUploadField; + +class EnquiryTab extends ConsumerStatefulWidget { + const EnquiryTab({super.key}); + @override + ConsumerState createState() => EnquiryTabState(); +} + +class EnquiryTabState extends ConsumerState { + List> dataVal = []; + + final TextEditingController _searchController = TextEditingController(); + + late ApiService apiService; + final _formKey = GlobalKey(); + final GlobalKey>> dropDownKey = + GlobalKey>>(); + final GlobalKey>> + dropDownKeyInsurer = GlobalKey>>(); + + List tabHeader = [ + 'name', + 'email', + 'mobile', + 'code', + 'address', + 'regNo', + 'remarks', + ]; + late String isActive = "1"; + html.File? docUploadedRCFile; + html.File? docUploadedIDProof; + html.File? docUploadedPrevPolicy; + // PlatformFile? passportFile; + String? selectedRCFile; + String? selectedIdProof; + String? selectedPrevPolicy; + String? passportFileUrlFromApi; + String? selectedId; + bool isLoading = false; + + String? selectedVehicleType; + String? selectedInsurer; + + Map controllers = {}; + String? _token; + dynamic userId; + dynamic managerId; + + List> getVehicleTypeData = []; + List> filteredVechicleData = []; + + List> getInsurersData = []; + List> filteredInsurersData = []; + + Map dataDetails() { + // final data = { + // "name": controllers["name"]?.text, + // "email": controllers["email"]?.text, + // "mobile": controllers["mobile"]?.text, + // "address": controllers["address"]?.text, + // "agent_code": controllers["code"]?.text, + // "is_active": isActive, + // "manager_id": managerId, + // }; + final data = { + "agent_id": 1, + "name": controllers["name"]?.text, + "mobile": controllers["mobile"]?.text, + "email": controllers["email"]?.text, + "reg_no": controllers["regNo"]?.text, + "vehicle_type_id": selectedVehicleType, + "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; + } + + @override + void initState() { + super.initState(); + apiService = ApiService(); + + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + // updateData(); + _initializeToken(); + Future.microtask(() { + managerId = ref.watch(managerIdProvider); + userId = ref.watch(userIdProvider); + }); + + getVehicleType(); + getInsurers(); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + 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 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 handleSave() async { + print("Handl1"); + final dataSet = dataDetails(); + print("dataSetAgent - $dataSet"); + print("Handl13f"); + if (!_formKey.currentState!.validate()) return; + // if (passportFile == null) { + // print("❌ No file selected!"); + // ScaffoldMessenger.of(context).showSnackBar( + // const SnackBar(content: Text("Please select a file before submitting")), + // ); + // return; + // } + + setState(() { + // uploadIncentiveData(dataSet); + }); + + print("Handl2"); + } + + // Future uploadIncentiveData(Map dataSet) async { + // final uri = Uri.parse('${Env.apiUrl}agent/uploadAgentIncentiveFile'); + // // 'https://venbait.in/nhance/partner/dev/api/agent/uploadAgentIncentiveFile', + // if (_token == null) { + // throw Exception('Token not found. Please log in.'); + // } + // // Use MultipartRequest (POST only) + // final request = http.MultipartRequest('POST', uri); + // request.headers['Authorization'] = 'Bearer $_token'; + // request.headers['app-signature'] = + // 'nhance-partner-2025-signature-35468846JRhH551HK'; + // + // print("USerDAta - $dataSet"); + // + // dataSet.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + // + // // Attach file if selected + // if (passportFile != null) { + // try { + // final reader = html.FileReader(); + // reader.readAsArrayBuffer(passportFile!); + // await reader.onLoad.first; + // + // final data = reader.result as Uint8List; + // + // final multipartFile = http.MultipartFile.fromBytes( + // 'incentive_file_name', + // data, + // filename: passportFile!.name, + // ); + // + // request.files.add(multipartFile); + // print("📎 File attached: ${passportFile!.name}"); + // } catch (e) { + // print("❌ Failed to read file: $e"); + // } + // } else { + // print("⚠️ No passport file selected."); + // } + // + // 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!"); + // + // print("📨 Response: ${response.body}"); + // + // final data = dataDetails(); // this is a Map + // final agentId = data["agent_id"]; + // + // getAgentIncenctiveFileList(agentId); + // // context.go(AppRoutes.agentLst); + // } else { + // print("❌ Submission failed. Status: ${response.statusCode}"); + // print("📨 Body: ${response.body}"); + // + // // Sort by created_on (latest first) + // + // showDialog( + // context: context, + // builder: (BuildContext context) { + // return AlertDialog( + // title: Text("Agent Creation Failed"), + // content: Text( + // "There was a problem in creating user. 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 Container( + // color: Colors.green, + decoration: BoxDecoration( + color: Color(0xffEDF6F5), + borderRadius: BorderRadius.circular(10.0), + ), + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.8, + padding: EdgeInsets.all(26.0), + child: Column( + children: [ + // Row(children: [Expanded(child: buildFormFields(context))]), + Expanded( + child: SingleChildScrollView(child: buildFormFields(context)), + ), + + const SizedBox(height: 20), + + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + handleSave(); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 45.0, vertical: 8), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text('Save', style: TextStyle(color: Colors.white)), + ), + ), + ], + ), + SizedBox(height: 30), + ], + ), + ); + } + + Widget buildFormFields(BuildContext context) { + return Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildResponsiveRow(context, buildName(context), buildEmail(context)), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + + _buildResponsiveRow( + context, + buildPhNumber(context), + buildId(context), + ), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + + _buildResponsiveRow( + context, + buildVehicleType(context), + buildInsurer(context), + ), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + + _buildResponsiveRow( + context, + buildUploadRCDocument(context), + buildUploadIDDocument(context), + ), + + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 20), + _buildResponsiveRow( + context, + buildUploadPolicyDocument(context), + buildRemarks(context), + ), + ], + ), + ); + } + + Widget _buildResponsiveRow( + BuildContext context, + Widget first, + Widget second, + ) { + 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: 25), + Expanded(child: second), + ], + ); + } + } + + 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: [ + Text(label, style: _textStyle), + const SizedBox(width: 10), + field, + ], + ); + } + } + + Widget buildResponsiveUploadField({ + required String label, + required String? hintText, + required void Function(String fileName, dynamic file) onFileSelected, + }) { + final isMobile = ResponsiveLayout.isMobile(context); + + // final uploadWidget = ThemedUploadField( + // hintText: hintText ?? "Upload Document", + // txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26, + // onFileSelected: onFileSelected, + // ); + + final uploadWidget = ThemedUploadField( + hintText: hintText ?? "Upload Document", + txtwidth: MediaQuery.of(context).size.width * 0.26, + onFileSelected: onFileSelected, + ); + + if (isMobile) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: _textStyle), + const SizedBox(height: 8), + uploadWidget, + const SizedBox(height: 16), + ], + ); + } else { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(label, style: _textStyle), + const SizedBox(width: 10), + uploadWidget, + ], + ); + } + } + + Widget buildName(BuildContext context) { + return buildResponsiveField( + label: "Name *", + field: ThemedFormField( + controller: controllers['name']!, + validator: (value) => Validators.requiredField(value, "name"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildEmail(BuildContext context) { + return buildResponsiveField( + label: "Email *", + field: ThemedFormField( + controller: controllers['email']!, + validator: (value) => Validators.email(value, "email"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPhNumber(BuildContext context) { + return buildResponsiveField( + label: "Phone Number *", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildId(BuildContext context) { + return buildResponsiveField( + label: "Registration Number *", + field: ThemedFormField( + controller: controllers['regNo']!, + validator: (value) => Validators.requiredField(value, "regNo"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildVehicleType(BuildContext context) { + return buildResponsiveField( + label: "Vehicle Type", + field: Container( + color: Colors.white, + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + // height: 40, + child: DropdownSearch>( + key: dropDownKey, + selectedItem: null, + items: (filter, infiniteScrollProps) { + return filteredVechicleData; + }, + + itemAsString: (val) => val['vehicle_type'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Vehicle Type", + ).copyWith( + filled: true, + fillColor: Colors.white, // 👈 makes the dropdown input white + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + filled: true, + fillColor: Colors.white, + hintText: "Search Vehicle 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 vehicle_type : ${val['vehicle_type']}"); + print("Id: ${val['id']}"); + selectedVehicleType = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ); + } + + Widget buildInsurer(BuildContext context) { + return buildResponsiveField( + label: "Insurer", + field: Container( + color: Colors.white, + width: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + // height: 40, + child: DropdownSearch>( + key: dropDownKeyInsurer, + selectedItem: null, + items: (filter, infiniteScrollProps) { + return filteredInsurersData; + }, + + itemAsString: (val) => val['name'].toString(), // what to show + compareFn: (item, selectedItem) => + item['id'] == selectedItem['id'], // ✅ compare by id + decoratorProps: DropDownDecoratorProps( + decoration: + AppInputDecorations.dropdownDecoration( + label: "Select Insurer", + ).copyWith( + filled: true, + fillColor: Colors.white, // 👈 makes the dropdown input white + ), + ), + + popupProps: PopupProps.menu( + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: MenuProps( + backgroundColor: + Colors.white, // 👈 sets dropdown background to white + ), + showSearchBox: true, + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + filled: true, + fillColor: Colors.white, + hintText: "Search Insurer...", + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), // 👈 Normal border + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + width: 1.5, + ), // 👈 Focused border + ), + ), + ), + // constraints: BoxConstraints(), + ), + + onChanged: (val) { + if (val != null) { + print("Selected Insurer : ${val['name']}"); + print("Id: ${val['id']}"); + selectedInsurer = val['id']; + // controllers['agentId']?.text = val['agent_code']; + // agentId = agent['id']; + } + }, + ), + ), + ); + } + + Widget buildUploadRCDocument(BuildContext context) { + return buildResponsiveUploadField( + label: "Upload RC Document", + hintText: selectedRCFile, + onFileSelected: (fileName, file) { + print("File picked: $fileName"); + setState(() { + docUploadedRCFile = file; + }); + }, + ); + } + + Widget buildUploadIDDocument(BuildContext context) { + return buildResponsiveUploadField( + label: "Upload ID Proof", + hintText: selectedIdProof, + onFileSelected: (fileName, file) { + print("File picked: $fileName"); + setState(() { + docUploadedIDProof = file; + }); + }, + ); + } + + Widget buildUploadPolicyDocument(BuildContext context) { + return buildResponsiveUploadField( + label: "Upload Previous Policy", + hintText: selectedPrevPolicy, + onFileSelected: (fileName, file) { + print("File picked: $fileName"); + setState(() { + docUploadedPrevPolicy = file; + }); + }, + ); + } + + Widget buildRemarks(BuildContext context) { + return buildResponsiveField( + label: "Remarks", + field: ThemedFormField( + maxLength: 3, + controller: controllers['remarks']!, + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + static const _textStyle = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + ); +} diff --git a/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart b/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart new file mode 100644 index 0000000..a8ed778 --- /dev/null +++ b/lib/presentation/screens/Enquiry/enquiry/policy_tab.dart @@ -0,0 +1,436 @@ +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 '../../../../core/services/api_service.dart'; +import '../../../../data/services/auth_service.dart'; +import '../../../../data/utils/Pagination.dart'; +import '../../../../data/utils/validators.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../themes/indicators/export_btn.dart'; +import '../../../themes/indicators/search_field_theme.dart'; +import '../../../themes/indicators/text_field_theme.dart'; + +class PolicyTab extends ConsumerStatefulWidget { + const PolicyTab({super.key}); + @override + ConsumerState createState() => PolicyTabState(); +} + +class PolicyTabState extends ConsumerState { + List> dataVal = []; + + final TextEditingController _searchController = TextEditingController(); + + List> getQuotationData = []; + List> originalData = []; + List> filteredData = []; + + late ApiService apiService; + final _formKey = GlobalKey(); + bool isLoading = false; + + List tabHeader = [ + 'name', + 'email', + 'mobile', + 'code', + 'address', + 'regNo', + ]; + + Map controllers = {}; + String? _token; + dynamic userId; + dynamic managerId; + + @override + void initState() { + super.initState(); + apiService = ApiService(); + + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + // updateData(); + _initializeToken(); + Future.microtask(() { + managerId = ref.watch(managerIdProvider); + userId = ref.watch(userIdProvider); + + getQuotationList(managerId); + }); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + Future getQuotationList(int managerId) async { + print('getClaimList called MagId - $managerId'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchQuotationList(managerId); + + if (response['status'] == 'success') { + print('quoationListData - ${response['data']}'); + setState(() { + getQuotationData = List>.from(response['data']); + originalData = getQuotationData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getQuotationData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + @override + Widget build(BuildContext context) { + return Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + children: [ + Container( + // color: Colors.green, + decoration: BoxDecoration( + color: Color(0xffEDF6F5), + borderRadius: BorderRadius.circular(10.0), + ), + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.8, + padding: EdgeInsets.all(26.0), + child: Column( + children: [ + SingleChildScrollView(child: buildFormFields(context)), + + const SizedBox(height: 20), + ], + ), + ), + const SizedBox(height: 20), + Container( + // color: Colors.green, + decoration: BoxDecoration( + color: Color(0xffEDF6F5), + borderRadius: BorderRadius.circular(10.0), + ), + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.8, + padding: EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('More Information', style: _headerStyle), + Row( + children: [ + SizedBox( + width: 100, + child: Text('Claim', style: _headerStyle), + ), + SizedBox(width: 20), + Expanded( + child: Container( + padding: EdgeInsets.all(6.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), + + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('', style: _headerStyle), + IconButton( + onPressed: () {}, + icon: Icon(Icons.add), + ), + ], + ), + ), + ), + ], + ), + SizedBox(height: 10), + Row( + children: [ + SizedBox( + width: 100, + child: Text('Endorsement', style: _headerStyle), + ), + SizedBox(width: 20), + Expanded( + child: Container( + padding: EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(6.0), + ), + + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('', style: _headerStyle), + IconButton( + onPressed: () {}, + icon: Icon(Icons.add), + ), + ], + ), + ), + ), + ], + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + // handleSave(); + }, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 45.0, + vertical: 8, + ), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text( + 'Save', + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ), + // SizedBox(height: 30), + // _buildDataTable(context), + ], + ), + ), + ], + ), + ), + ); + } + + Widget buildFormFields(BuildContext context) { + return Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildResponsiveRow( + context, + buildName(context), + buildInsusrer(context), + ), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + + _buildResponsiveRow( + context, + buildIdv(context), + buildInsurdName(context), + ), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + + _buildResponsiveRow( + context, + buildPolicyNum(context), + buildPaymentMode(context), + ), + + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + + _buildResponsiveRow( + context, + buildPlanType(context), + buildPremiumAmount(context), + ), + ], + ), + ); + } + + Widget _buildResponsiveRow( + BuildContext context, + Widget first, + Widget second, + ) { + 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: 25), + Expanded(child: second), + ], + ); + } + } + + 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: [ + Text(label, style: _textStyle), + const SizedBox(width: 10), + field, + ], + ); + } + } + + Widget buildName(BuildContext context) { + return buildResponsiveField( + label: "Registration Number", + field: ThemedFormField( + controller: controllers['name']!, + validator: (value) => Validators.requiredField(value, "name"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildInsusrer(BuildContext context) { + return buildResponsiveField( + label: "Insusrer", + field: ThemedFormField( + controller: controllers['email']!, + validator: (value) => Validators.email(value, "email"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildIdv(BuildContext context) { + return buildResponsiveField( + label: "IDV", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildInsurdName(BuildContext context) { + return buildResponsiveField( + label: "Insured Name", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPolicyNum(BuildContext context) { + return buildResponsiveField( + label: "Policy Number", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPaymentMode(BuildContext context) { + return buildResponsiveField( + label: "Payment Mode", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPlanType(BuildContext context) { + return buildResponsiveField( + label: "Plan Type", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPremiumAmount(BuildContext context) { + return buildResponsiveField( + label: "Premium Amount", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + static const _headerStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ); + + static const _textStyle = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + ); +} diff --git a/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart b/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart new file mode 100644 index 0000000..7612ffb --- /dev/null +++ b/lib/presentation/screens/Enquiry/enquiry/quotation_tab.dart @@ -0,0 +1,745 @@ +import 'dart:io' as html; +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 '../../../../core/services/api_service.dart'; +import '../../../../data/services/auth_service.dart'; +import '../../../../data/utils/validators.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; +import '../../../themes/indicators/customizd_file_upload.dart'; +import '../../../themes/indicators/input_field_decoration.dart'; +import '../../../themes/indicators/text_field_theme.dart'; +import '../../../themes/indicators/upload_doc_theme.dart' + hide ThemedUploadField; + +class QuotationTab extends ConsumerStatefulWidget { + const QuotationTab({super.key}); + @override + ConsumerState createState() => QuotationTabState(); +} + +class QuotationTabState extends ConsumerState { + int currentPage = 0; + int itemsPerPage = 10; + + List> dataVal = []; + + final TextEditingController _searchController = TextEditingController(); + + late ApiService apiService; + final _formKey = GlobalKey(); + final GlobalKey>> dropDownKey = + GlobalKey>>(); + + List tabHeader = [ + 'name', + 'email', + 'mobile', + 'code', + 'address', + 'regNo', + ]; + late String isActive = "1"; + html.File? docUploadedFile; + + // PlatformFile? passportFile; + String? selectedFileNames; + String? passportFileUrlFromApi; + String? selectedId; + bool isLoading = false; + bool isquotation = false; + + Map controllers = {}; + String? _token; + dynamic userId; + dynamic managerId; + + List> getVehicleTypeData = []; + List> filteredVechicleData = []; + + List> getInsurersData = []; + List> filteredInsurersData = []; + + Map dataDetails() { + final data = { + "name": controllers["name"]?.text, + "email": controllers["email"]?.text, + "mobile": controllers["mobile"]?.text, + "address": controllers["address"]?.text, + "agent_code": controllers["code"]?.text, + "is_active": isActive, + "manager_id": managerId, + }; + return data; + } + + List> getQuotationData = []; + List> originalData = []; + List> filteredData = []; + // bool isLoading = false; + + @override + void initState() { + super.initState(); + apiService = ApiService(); + + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + // updateData(); + _initializeToken(); + Future.microtask(() { + managerId = ref.watch(managerIdProvider); + userId = ref.watch(userIdProvider); + + getQuotationList(managerId); + }); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("APISERTOKEN - $_token"); + } + + Future getQuotationList(int managerId) async { + print('getClaimList called MagId - $managerId'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchQuotationList(managerId); + + if (response['status'] == 'success') { + print('quoationListData - ${response['data']}'); + setState(() { + getQuotationData = List>.from(response['data']); + originalData = getQuotationData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getQuotationData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + @override + Widget build(BuildContext context) { + return Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + children: [ + Container( + // color: Colors.green, + decoration: BoxDecoration( + color: Color(0xffEDF6F5), + borderRadius: BorderRadius.circular(10.0), + ), + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.8, + padding: EdgeInsets.all(16.0), + child: Column( + children: [ + // Text('datta') + _buildDataTable(context), + ], + ), + ), + + const SizedBox(height: 20), + if (isquotation) + Container( + // color: Colors.green, + decoration: BoxDecoration( + color: Color(0xffEDF6F5), + borderRadius: BorderRadius.circular(10.0), + ), + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height * 0.8, + padding: EdgeInsets.all(26.0), + child: Column( + children: [ + SingleChildScrollView(child: buildFormFields(context)), + + const SizedBox(height: 20), + + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: () { + // handleSave(); + }, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 45.0, + vertical: 8, + ), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text( + 'Reject', + style: TextStyle(color: Colors.white), + ), + ), + ), + const SizedBox(width: 10), + GestureDetector( + onTap: () { + // handleSave(); + }, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 45.0, + vertical: 8, + ), + + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8.0), + color: Color(0xFF425B5B), + ), + child: Text( + 'Accept', + style: TextStyle(color: Colors.white), + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget buildFormFields(BuildContext context) { + return Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildResponsiveRow( + context, + buildName(context), + buildInsusrer(context), + ), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + + _buildResponsiveRow( + context, + buildIdv(context), + buildPremiumAmnt(context), + ), + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + + _buildResponsiveRow( + context, + buildPlanType(context), + buildDocuments(context), + ), + + if (!ResponsiveLayout.isMobile(context)) const SizedBox(height: 10), + _buildResponsiveRow( + context, + buildAdditonalDocuments(context), + buildRemarks(context), + ), + ], + ), + ); + } + + Widget _buildResponsiveRow( + BuildContext context, + Widget first, + Widget second, + ) { + 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: 25), + Expanded(child: second), + ], + ); + } + } + + Widget buildName(BuildContext context) { + return buildResponsiveField( + label: "Registration Number", + field: ThemedFormField( + controller: controllers['name']!, + validator: (value) => Validators.requiredField(value, "name"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildInsusrer(BuildContext context) { + return buildResponsiveField( + label: "Insusrer", + field: ThemedFormField( + controller: controllers['email']!, + validator: (value) => Validators.email(value, "email"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildIdv(BuildContext context) { + return buildResponsiveField( + label: "IDV", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPremiumAmnt(BuildContext context) { + return buildResponsiveField( + label: "Premium Amount", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildPlanType(BuildContext context) { + return buildResponsiveField( + label: "Plan Type", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildDocuments(BuildContext context) { + return buildResponsiveUploadField( + label: "Upload RC Certificate", + hintText: selectedFileNames, + onFileSelected: (fileName, file) { + print("File picked: $fileName"); + setState(() { + docUploadedFile = file; + }); + }, + ); + } + + Widget buildAdditonalDocuments(BuildContext context) { + return buildResponsiveField( + label: "Additional Documents", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget buildRemarks(BuildContext context) { + return buildResponsiveField( + label: "Remarks", + field: ThemedFormField( + controller: controllers['mobile']!, + validator: (value) => Validators.phone(value, "phNumber"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + 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: [ + Text(label, style: _textStyle), + const SizedBox(width: 10), + field, + ], + ); + } + } + + Widget buildResponsiveUploadField({ + required String label, + required String? hintText, + required void Function(String fileName, dynamic file) onFileSelected, + }) { + final isMobile = ResponsiveLayout.isMobile(context); + + final uploadWidget = ThemedUploadField( + hintText: hintText ?? "Upload Document", + txtwidth: isMobile ? null : MediaQuery.of(context).size.width * 0.26, + onFileSelected: onFileSelected, + ); + + if (isMobile) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: _textStyle), + const SizedBox(height: 8), + uploadWidget, + const SizedBox(height: 16), + ], + ); + } else { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(label, style: _textStyle), + const SizedBox(width: 10), + uploadWidget, + ], + ); + } + } + + Widget buildId(BuildContext context) { + return buildResponsiveField( + label: "Registration Number *", + field: ThemedFormField( + controller: controllers['regNo']!, + validator: (value) => Validators.requiredField(value, "regNo"), + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.26, + ), + ); + } + + Widget _buildDataTable5(BuildContext context) { + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + return ListView.builder( + itemCount: ResponsiveLayout.isMobile(context) + ? sortedData + .length // only cards for mobile + : sortedData.length + 1, // +1 for header in desktop + itemBuilder: (context, index) { + if (!ResponsiveLayout.isMobile(context) && index == 0) { + return _buildHeader(); + } + + final startIndex = (currentPage - 1) * itemsPerPage; + final item = + sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)]; + final sno = startIndex + index; + + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); + }, + ); + } + + Widget _buildDataTable(BuildContext context) { + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + return SingleChildScrollView( + child: Column( + children: [ + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: ResponsiveLayout.isMobile(context) + ? sortedData + .length // only cards for mobile + : sortedData.length + 1, // +1 for header in desktop + itemBuilder: (context, index) { + if (!ResponsiveLayout.isMobile(context) && index == 0) { + return _buildHeader(); + } + + final startIndex = (currentPage - 1) * itemsPerPage; + final item = + sortedData[index - + (ResponsiveLayout.isMobile(context) ? 0 : 1)]; + final sno = startIndex + index; + + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); + }, + ), + ], + ), + ); + } + + Widget _buildHeader() { + return Container( + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: const Row( + children: [ + Expanded(flex: 1, child: Text(' ', style: _headerStyle)), + Expanded( + flex: 1, + child: Text('Registration Number', style: _headerStyle), + ), + Expanded(flex: 1, child: Text('Insurer', style: _headerStyle)), + Expanded(flex: 1, child: Text('IDV', style: _headerStyle)), + Expanded(flex: 1, child: Text('Plan Type', style: _headerStyle)), + Expanded(flex: 1, child: Text('Premium Amount', style: _headerStyle)), + Expanded(flex: 1, child: Text('Status', style: _headerStyle)), + ], + ), + ); + } + + Widget _buildDataRow(Map item, sno) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16), + // margin: const EdgeInsets.only(top: 10), + decoration: BoxDecoration( + color: Colors.white, + // color: Color(0xFFE0F7F9), + border: const Border( + bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + // ✅ Single-select checkbox + Expanded( + flex: 1, + child: Checkbox( + value: selectedId == item['id'], // only selected row is checked + onChanged: (val) { + setState(() { + if (val == true) { + selectedId = item['id']; // select this row + isquotation = true; + } else { + selectedId = null; + isquotation = false; // unselect + } + }); + print("Selected row id: $selectedId"); + }, + ), + ), + + Expanded(flex: 1, child: Text(item['id'] ?? '-', style: _dataBold)), + Expanded( + flex: 1, + child: Text(item['email'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 1, + child: Text(item['mobile'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 1, + child: Text(item['insurance_plan_type'] ?? '-', style: _dataBold), + ), + Expanded( + flex: 1, + child: Text( + item['insured_declared_value'] ?? '-', + style: _dataBold, + ), + ), + Expanded( + flex: 1, + child: Text( + item['status'] ?? '-', + style: TextStyle( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: item['status'] == 'Accepted' ? Colors.green : Colors.red, + ), + ), + ), + ], + ), + ); + } + + Widget _buildDataCard(Map item, int sno) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xFFF6FEFD), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: const Color(0xffD9EBE8)), + ), + child: Row( + children: [ + Column( + children: [ + // ✅ Single-select checkbox + Checkbox( + value: selectedId == item['id'], // only selected row is checked + onChanged: (val) { + setState(() { + if (val == true) { + selectedId = item['id']; // select this row + isquotation = true; + } else { + selectedId = null; + isquotation = false; // unselect + } + }); + print("Selected row id: $selectedId"); + }, + ), + ], + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Company + Vehicle Reg No + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text("New India", style: _cardBodyStyle), + const Text("TN64V3456", style: _cardheaderStyle), + const Text("Status: Rejected", style: _cardBodyStyle), + ], + ), + ), + SizedBox(width: 5), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text("Comprehensive", style: _cardBodyStyle), + const Text("IDV:₹145000", style: _cardBodyStyle), + const Text("₹1000", style: _cardheaderStyle), + ], + ), + ), + ], + ), + ], + ), + ), + ], + ), + ); + } + + static final _dataBold = TextStyle( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = TextStyle( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + static const _headerStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ); + + static const _textStyle = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + ); + + static const _cardheaderStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static const _cardBodyStyle = TextStyle( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); +} diff --git a/lib/presentation/screens/Enquiry/enquiry/tabs.dart b/lib/presentation/screens/Enquiry/enquiry/tabs.dart new file mode 100644 index 0000000..57258fe --- /dev/null +++ b/lib/presentation/screens/Enquiry/enquiry/tabs.dart @@ -0,0 +1,127 @@ +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 '../../../../core/routing/routes.dart'; +import 'enquiry_tab.dart'; +import 'quotation_tab.dart'; +import 'policy_tab.dart'; +import '../../../layouts/main_layout.dart'; + +class TabEnquiryList extends ConsumerStatefulWidget { + const TabEnquiryList({super.key}); + @override + ConsumerState createState() => TabEnquiryListState(); +} + +class TabEnquiryListState extends ConsumerState { + int selectedIndex = 0; // 0 = Enquiry, 1 = Quotation, 2 = Policy + + final List tabs = ["Enquiry", "Quotation", "Policy"]; + final List tabWidgets = [EnquiryTab(), QuotationTab(), PolicyTab()]; + + @override + Widget build(BuildContext context) { + return MainLayout( + title: "Enquiry", + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + // Header + Padding( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + child: GestureDetector( + onTap: () { + context.go(AppRoutes.dashboard); + }, + child: Row( + children: [ + const Icon( + Icons.arrow_left_sharp, + size: 35, + color: Color(0xFF425B5B), + ), + const SizedBox(width: 8), + Text( + "Enquiry", + style: GoogleFonts.inter( + fontSize: 18, + fontWeight: FontWeight.w700, + color: Colors.black87, + ), + ), + ], + ), + ), + ), + + const SizedBox(height: 10), + + // Tab Buttons + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: List.generate(tabs.length, (index) { + final bool isSelected = selectedIndex == index; + return Padding( + padding: const EdgeInsets.only(right: 12), + child: ElevatedButton( + style: ElevatedButton.styleFrom( + elevation: 2, + backgroundColor: isSelected + ? const Color(0xFF425B5B) // selected dark green + : const Color(0xFFEDFFFC), // light teal + foregroundColor: isSelected + ? Colors.white + : Colors.black87, + side: BorderSide( + color: isSelected + ? const Color(0xFF425B5B) + : const Color(0xFFEDFFFC), + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + onPressed: () { + setState(() { + selectedIndex = index; + }); + }, + child: Text( + tabs[index], + style: GoogleFonts.inter( + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w500, + fontSize: 15, + ), + ), + ), + ); + }), + ), + ), + + const SizedBox(height: 16), + + // Tab content + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: tabWidgets[selectedIndex], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/screens/Enquiry/enquiryList.dart b/lib/presentation/screens/Enquiry/enquiryList.dart index 5d28a9e..9ea4d6f 100644 --- a/lib/presentation/screens/Enquiry/enquiryList.dart +++ b/lib/presentation/screens/Enquiry/enquiryList.dart @@ -1,21 +1,26 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import '../../../../core/routing/routes.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/utils/Pagination.dart'; import '../../layouts/main_layout.dart'; +import '../../layouts/responsive_layout.dart'; +import '../../providers/manager_provider.dart'; import '../../themes/indicators/export_btn.dart'; import '../../themes/indicators/search_field_theme.dart'; import '../../widgets/custom_action_popup.dart'; -class enquiryList extends StatefulWidget { - const enquiryList({super.key}); +class EnquiryList extends ConsumerStatefulWidget { + const EnquiryList({super.key}); @override - enquiryListState createState() => enquiryListState(); + ConsumerState createState() => EnquiryListState(); } -class enquiryListState extends State { +class EnquiryListState extends ConsumerState { int currentPage = 1; int itemsPerPage = 10; late ApiService apiService; @@ -31,70 +36,102 @@ class enquiryListState extends State { super.initState(); apiService = ApiService(); - // getStaffList(); + + Future.microtask(() { + final id = ref.read(managerIdProvider); + final roleId = ref.read(userRoleProvider); + + print("ENQroleId - $roleId"); + if (id != null) { + getStaffList(id, roleId); + } + }); + } + + Future getStaffList(int managerId, role) async { + print('getClaimList called MagId - $managerId - $role'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchEnquiryList(managerId, role); + + if (response['status'] == 'success') { + final data = response['data']; + print('getStaffListData - ${response['data']}'); + setState(() { + if (data is List) { + // Already a list of maps + getStaffData = List>.from(data); + } else if (data is Map) { + // Single object, wrap in a list + getStaffData = [Map.from(data)]; + } else { + getStaffData = []; + } + // getStaffData = List>.from(response['data']); + originalData = getStaffData; + filteredData = List.from(originalData); + // print('originalData - $getClaimPolicies'); + }); + } else { + getStaffData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } } List get _paginatedData { + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + final startIndex = (currentPage - 1) * itemsPerPage; - final endIndex = (currentPage * itemsPerPage).clamp(0, filteredData.length); - return filteredData.sublist(startIndex, endIndex); + final endIndex = (currentPage * 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"; + // final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive"; - return (item['name'] ?? '').toLowerCase().contains( + return (item['created_on'] ?? '').toLowerCase().contains( query.toLowerCase(), ) || - (item['email'] ?? '').toLowerCase().contains(query.toLowerCase()) || - (item['mobile'] ?? '').toLowerCase().contains( + (item['reg_no'] ?? '').toLowerCase().contains( query.toLowerCase(), ) || - (item['address'] ?? '').toLowerCase().contains( + (item['insurer_name'] ?? '').toLowerCase().contains( query.toLowerCase(), ) || - (item['emp_id'] ?? item['agent_code'] ?? '').toLowerCase().contains( + (item['status'] ?? '').toLowerCase().contains( query.toLowerCase(), ) || - isActiveStatus.contains(query.toLowerCase()); + (item['remarks'] ?? '').toLowerCase().contains(query.toLowerCase()); }).toList(); }); } final TextEditingController _searchStaffController = TextEditingController(); - // Future getStaffList() async { - // print('getClaimList called'); - // setState(() { - // isLoading = true; - // }); - // - // try { - // final response = await apiService.fetchStaffUserList(); - // - // if (response['status'] == 'success') { - // print('getStaffListData - ${response['data']}'); - // setState(() { - // getStaffData = List>.from(response['data']); - // originalData = getStaffData; - // filteredData = List.from(originalData); - // // print('originalData - $getClaimPolicies'); - // }); - // } else { - // getStaffData = []; - // originalData = []; - // } - // } catch (e) { - // print('Exception occurred: $e'); - // } finally { - // setState(() { - // isLoading = false; - // }); - // } - // } + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat('dd/MM/yyyy HH:mm').format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } List _buildPopupMenuActions(BuildContext context, dynamic data) { return [ @@ -103,7 +140,7 @@ class enquiryListState extends State { Navigator.pop(context); print('EDITStaff - ${data['id']}'); dynamic id = data['id']; - context.go('/staff/$id'); + // context.go('/staff/$id'); }, child: Row( mainAxisSize: MainAxisSize.min, @@ -145,7 +182,7 @@ class enquiryListState extends State { color: Color(0xFF425B5B), ), Text( - "Enquries", + "Enquiries", style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, @@ -179,29 +216,34 @@ class enquiryListState extends State { backgroundColor: Color(0xFFF6F8F8), onChanged: filterData, controller: _searchStaffController, - txtwidth: MediaQuery.of(context).size.width * 0.2, + txtwidth: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.width * 0.6 + : MediaQuery.of(context).size.width * 0.2, ), Spacer(), ExportBtn( - sheetName: "Staff", - fileName: "staff_list", + sheetName: "Enquiry", + fileName: "enquiry_list", data: filteredData, + txt: !ResponsiveLayout.isMobile(context) + ? true + : false, headers: [ "id", - "name", - "email", - "mobile", - "emp_id", - "is_active", + "created_on", + "reg_no", + "insurer_name", + "status", + "remarks", ], ), SizedBox(width: 10), GestureDetector( onTap: () { - print('Export'); + // print('Export'); }, child: Container( padding: EdgeInsets.all(8.0), @@ -214,22 +256,24 @@ class enquiryListState extends State { children: [ Icon(Icons.add, color: Colors.white), - SizedBox(width: 10), + if (!ResponsiveLayout.isMobile(context)) ...[ + SizedBox(width: 10), - GestureDetector( - onTap: () { - // context.go(AppRoutes.agent / create); - context.go('/staff/create'); - }, - child: Text( - 'Create New Staff', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14, + GestureDetector( + onTap: () { + // context.go(AppRoutes.agent / create); + context.go('/staff/create'); + }, + child: Text( + 'Create New Staff', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 14, + ), ), ), - ), + ], ], ), ), @@ -238,6 +282,51 @@ class enquiryListState extends State { ), ), SizedBox(height: 10), + Container( + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: const Row( + children: [ + Expanded( + flex: 1, + child: Text('S.No.', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text( + 'Received Date & Time', + style: _headerStyle, + ), + ), + Expanded( + flex: 1, + child: Text('Reg.No.', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Company', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Status', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Remarks', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Action', style: _headerStyle), + ), + ], + ), + ), Expanded(child: _buildDataTable(context)), ], ), @@ -281,47 +370,31 @@ class enquiryListState extends State { ); } - final sortedData = [...filteredData] - ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); - + final sortedData = [..._paginatedData]; return ListView.builder( - // itemCount: filteredData.length + 1, // +1 for header, +1 for pagination - itemCount: sortedData.length + 1, // +1 for header, +1 for pagination + itemCount: ResponsiveLayout.isMobile(context) + ? sortedData + .length // only cards for mobile + : sortedData.length + 1, // +1 for header in desktop itemBuilder: (context, index) { - if (index == 0) return _buildHeader(); - // if (index == dataVal.length + 1) - // return _buildPagination(context); - final startIndex = ((currentPage - 1) * itemsPerPage); - // final item = filteredData[index - 1]; - final item = sortedData[index - 1]; + if (!ResponsiveLayout.isMobile(context) && index == 0) { + return _buildHeader(); + } + + final startIndex = (currentPage - 1) * itemsPerPage; + final item = + sortedData[index - (ResponsiveLayout.isMobile(context) ? 0 : 1)]; final sno = startIndex + index; - return _buildDataRow(item, sno); + + return !ResponsiveLayout.isMobile(context) + ? _buildDataRow(item, sno) + : _buildDataCard(item, sno); }, ); } Widget _buildHeader() { - return Container( - decoration: BoxDecoration( - color: Color(0xFFEDF6F5), - borderRadius: BorderRadius.circular(6), - ), - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), - child: const Row( - children: [ - Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)), - Expanded( - flex: 2, - child: Text('Received Date & Time', style: _headerStyle), - ), - Expanded(flex: 3, child: Text('Reg.No.', style: _headerStyle)), - Expanded(flex: 2, child: Text('Company', style: _headerStyle)), - Expanded(flex: 1, child: Text('Status', style: _headerStyle)), - Expanded(flex: 1, child: Text('Remarks', style: _headerStyle)), - Expanded(flex: 1, child: Text('Action', style: _headerStyle)), - ], - ), - ); + return SizedBox.shrink(); } Widget _buildDataRow(Map item, sno) { @@ -339,42 +412,38 @@ class enquiryListState extends State { child: Row( children: [ Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)), - Expanded(flex: 2, child: Text(item['name'] ?? '-', style: _dataBold)), Expanded( - flex: 3, - child: Text(item['email'] ?? '-', style: _dataBold), + flex: 2, + child: Text( + _formatDate(item['created_on']) ?? '-', + style: _dataBold, + ), + ), + Expanded( + flex: 1, + child: Text(item['reg_no'] ?? '-', style: _dataBold), ), Expanded( flex: 2, - child: Text(item['mobile'] ?? '-', style: _dataBold), - ), - Expanded( - flex: 1, - child: Text(item['emp_id'] ?? '-', style: _dataBold), + child: Text( + item['insurer_name'] ?? '-', + style: _dataBold, + softWrap: true, + maxLines: 3, + ), ), + Expanded( + flex: 2, + child: Text(item['status'] ?? '-', style: _dataBold), + ), Expanded( flex: 1, - child: Transform.scale( - scale: 0.6, // reduce size (0.7–0.9 works well) - child: Switch( - value: item['is_active'] == "1", - onChanged: (val) { - setState(() { - item['is_active'] = val ? "1" : "0"; - }); - final response = apiService.updateStatus( - item['id'], - val ? "1" : "0", - 'staff', - ); - print("Response - $response"); - }, - activeColor: Color(0xFF425B5B), // thumb when active - activeTrackColor: Color(0xFFB2D8D3), // track when active - inactiveThumbColor: Colors.grey.shade400, // thumb when inactive - inactiveTrackColor: Colors.grey.shade300, // track when inactive - ), + child: Text( + item['remarks'] ?? '-', + style: _dataBold, + softWrap: true, + maxLines: 3, ), ), @@ -415,6 +484,123 @@ class enquiryListState extends State { ); } + Widget _buildDataCard(Map item, int sno) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8), + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xFFF6FEFD), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: const Color(0xffD9EBE8)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(item['reg_no'] ?? '-', style: _headerStyle), + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: Offset(0, 30), + icon: Icon(Icons.more_vert, color: Color(0xFF475569), size: 14), + itemBuilder: (context) => [ + CustomPopupMenuEntry( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: _buildPopupMenuActions(context, item), + ), + ), + ), + ], + ), + ], + ), + const Divider(color: Color(0xffD9EBE8), thickness: 0.8), + + // Company + Vehicle Reg No + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text("Company", style: _cardheaderStyle), + Text( + item['insurer_name'] ?? '-', + style: _cardBodyStyle, + maxLines: 3, + softWrap: true, + ), + ], + ), + ), + SizedBox(width: 5), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text("Status", style: _cardheaderStyle), + Text( + item['status'] ?? '-', + style: _cardBodyStyle, + maxLines: 2, + softWrap: true, + ), + ], + ), + ), + ], + ), + const SizedBox(height: 15), + + // Created On + Remarks + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Received Date & Time", style: _cardheaderStyle), + Text( + _formatDate(item['created_on']) ?? '-', + style: _cardBodyStyle, + ), + ], + ), + ), + SizedBox(width: 5), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Remarks", style: _cardheaderStyle), + Text( + item['remarks'] ?? '-', + style: _cardBodyStyle, + maxLines: 3, + softWrap: true, + ), + ], + ), + ), + ], + ), + ], + ), + ); + } + static final _dataBold = TextStyle( fontSize: 14, @@ -432,4 +618,15 @@ class enquiryListState extends State { color: Colors.black, fontWeight: FontWeight.bold, ); + static const _cardheaderStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static const _cardBodyStyle = TextStyle( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); } diff --git a/lib/presentation/screens/UserManagement/Agent/agent.dart b/lib/presentation/screens/UserManagement/Agent/agent.dart index ad3b0f2..cbe0329 100644 --- a/lib/presentation/screens/UserManagement/Agent/agent.dart +++ b/lib/presentation/screens/UserManagement/Agent/agent.dart @@ -1,7 +1,9 @@ import 'dart:convert'; // import 'dart:io' as html; import 'dart:typed_data'; // Import for Uint8List +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_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -17,9 +19,11 @@ import '../../../../data/utils/validators.dart'; import '../../../layouts/main_layout.dart'; import '../../../providers/manager_provider.dart'; import '../../../providers/user_provider.dart'; +import '../../../themes/indicators/customizd_file_upload.dart'; import '../../../themes/indicators/export_btn.dart'; import '../../../themes/indicators/search_field_theme.dart'; -import '../../../themes/indicators/upload_doc_theme.dart'; +import '../../../themes/indicators/singleFileUpload.dart'; +// import '../../../themes/indicators/upload_doc_theme.dart'; import 'package:universal_html/html.dart' as html; class Agent extends ConsumerStatefulWidget { @@ -34,10 +38,12 @@ class AgentState extends ConsumerState { late ApiService apiService; List tabHeader = ['name', 'email', 'mobile', 'code', 'address']; late String isActive = "1"; - html.File? passportFile; + // html.File? docUploadedFile; + // PlatformFile? passportFile; String? selectedFileNames; String? passportFileUrlFromApi; String? selectedId; + PlatformFile? docUploadedFile; Map controllers = {}; String? _token; @@ -96,12 +102,15 @@ class AgentState extends ConsumerState { String? apiDocPath = data["certificate_file_name"]; if (apiDocPath != null && apiDocPath.isNotEmpty) { + print('apiDocPath - $apiDocPath'); selectedFileNames = apiDocPath.split('/').last; + print('selectedFileNames - $selectedFileNames'); passportFileUrlFromApi = apiDocPath; - passportFile = null; + print('passportFileUrlFromApi - $passportFileUrlFromApi'); + docUploadedFile = null; } else { selectedFileNames = null; - passportFile = null; + docUploadedFile = null; passportFileUrlFromApi = null; } }); @@ -155,33 +164,64 @@ class AgentState extends ConsumerState { print("USerDAta - $userData"); + // userData.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + userData.forEach((key, value) { - request.fields[key] = value.toString(); - print("✅ Encoded travel_details2: ${request.fields[key]}"); + if (key != 'certificate_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + } }); // Attach file if selected - if (passportFile != null) { + // if (docUploadedFile != null) { + // try { + // final reader = html.FileReader(); + // reader.readAsArrayBuffer(docUploadedFile!); + // await reader.onLoad.first; + // + // final data = reader.result as Uint8List; + // + // final multipartFile = http.MultipartFile.fromBytes( + // 'certificate_file_name', + // data, + // filename: docUploadedFile!.name, + // ); + // + // request.files.add(multipartFile); + // print("📎 File attached: ${docUploadedFile!.name}"); + // } catch (e) { + // print("❌ Failed to read file: $e"); + // } + // } else { + // print("⚠️ No passport file selected."); + // } + + // Attach file if selected + if (docUploadedFile != null) { try { - final reader = html.FileReader(); - reader.readAsArrayBuffer(passportFile!); - await reader.onLoad.first; - - final data = reader.result as Uint8List; - - final multipartFile = http.MultipartFile.fromBytes( - 'certificate_file_name', - data, - filename: passportFile!.name, - ); - - request.files.add(multipartFile); - print("📎 File attached: ${passportFile!.name}"); + if (docUploadedFile!.bytes != null) { + final multipartFile = http.MultipartFile.fromBytes( + 'certificate_file_name', + docUploadedFile!.bytes!, + filename: docUploadedFile!.name, + ); + request.files.add(multipartFile); + } else if (docUploadedFile!.path != null) { + final multipartFile = await http.MultipartFile.fromPath( + 'certificate_file_name', + docUploadedFile!.path!, + filename: docUploadedFile!.name, + ); + request.files.add(multipartFile); + } + print("📎 File attached: ${docUploadedFile!.name}"); } catch (e) { - print("❌ Failed to read file: $e"); + print("❌ Failed to attach file: $e"); } - } else { - print("⚠️ No passport file selected."); } print(" Sending request with fields: ${request.fields}"); @@ -227,6 +267,37 @@ class AgentState extends ConsumerState { } } + // Future _downloadFile() async { + // if (docUploadedFile != null) { + // try { + // if (kIsWeb) { + // // ✅ Web: use bytes + // final blob = html.Blob([docUploadedFile!.bytes!]); + // final url = html.Url.createObjectUrlFromBlob(blob); + // + // final anchor = html.AnchorElement(href: url) + // ..setAttribute('download', docUploadedFile!.name) + // ..click(); + // + // html.Url.revokeObjectUrl(url); + // print("Download triggered successfully (web)!"); + // } else { + // print("Local file path: ${docUploadedFile!.path}"); + // // Use open_filex to open it: + // // await OpenFilex.open(docUploadedFile!.path!); + // } + // } catch (e) { + // print("Error during download: $e"); + // } + // } else if (passportFileUrlFromApi != null) { + // print("Download from API: $passportFileUrlFromApi"); + // final path = + // 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId'; + // + // apiService.getPdfDownload(path, selectedId); + // } + // } + @override void dispose() { for (var controller in controllers.values) { @@ -451,7 +522,9 @@ class AgentState extends ConsumerState { children: [ Text("Upload Certificate", style: _textStyle), SizedBox(width: 10), + Column( + mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ ThemedUploadField( @@ -460,58 +533,25 @@ class AgentState extends ConsumerState { onFileSelected: (fileName, file) { print("Picked file: $fileName (${file.size} bytes)"); setState(() { - passportFile = file; + docUploadedFile = file; }); }, ), - SizedBox(height: 5), + const SizedBox(height: 5), - if (passportFile != null || passportFileUrlFromApi != null) - // Centers the text + if (docUploadedFile != null || passportFileUrlFromApi != null) Container( color: Colors.white, child: Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, children: [ GestureDetector( - onTap: () { - print('DOWNLOAD - $passportFile'); - - if (passportFile != null) { - try { - // Create a blob from the response body - final blob = html.Blob([passportFile!]); - - // Generate a download URL for the blob - final url = html.Url.createObjectUrlFromBlob(blob); - - // Create a link element to trigger the download - final anchor = html.AnchorElement(href: url) - ..setAttribute( - 'download', - selectedFileNames ?? "document.pdf", - ) - ..click(); - - // Revoke the download URL to free up resources - html.Url.revokeObjectUrl(url); - - print("Download triggered successfully!"); - } catch (e) { - print("Error during download: $e"); - } - } else if (passportFileUrlFromApi != null) { - print("Raw file path: $passportFileUrlFromApi"); - - final path = - 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId'; - - apiService.getPdfDownload(path, selectedId); - } else { - print("No file available to download."); - } - }, + onTap: () => apiService.downloadFile( + apiUrl: + 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId', + apiId: null, + localFile: docUploadedFile, + fileName: selectedFileNames, + ), child: Container( padding: const EdgeInsets.all(5), decoration: BoxDecoration( @@ -519,9 +559,7 @@ class AgentState extends ConsumerState { color: Colors.green.shade300, ), child: Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ + children: const [ Text( "Download", style: TextStyle( @@ -529,9 +567,6 @@ class AgentState extends ConsumerState { fontWeight: FontWeight.w200, color: Colors.white, ), - overflow: TextOverflow.ellipsis, - textAlign: TextAlign - .end, // Ensures text is centered within the Text widget ), SizedBox(width: 5), Icon(Icons.download, size: 13, color: Colors.white), @@ -544,23 +579,146 @@ class AgentState extends ConsumerState { ), ], ), - ], - ); - } - Widget buildIncentiveFile() { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("Incentive File", style: _textStyle), - SizedBox(width: 10), - ThemedUploadField( - hintText: "Upload Document", - txtwidth: MediaQuery.of(context).size.width * 0.26, - onFileSelected: (fileName, file) { - print("Picked file: $fileName (${file.size} bytes)"); - }, - ), + // Column( + // crossAxisAlignment: CrossAxisAlignment.end, + // children: [ + // ThemedUploadField( + // hintText: selectedFileNames ?? "Upload Document", + // txtwidth: MediaQuery.of(context).size.width * 0.26, + // + // onFileSelected: (fileName, file) { + // // print("File picked: ${fileName}"); + // // print("Size: ${file.size}"); + // // print("Path: ${file.path}"); // works on mobile/desktop + // // print("Bytes: ${file.bytes}"); + // print("Picked file: $fileName (${file.size} bytes)"); + // setState(() { + // docUploadedFile = file; + // }); + // }, + // ), + // SizedBox(height: 5), + // + // if (docUploadedFile != null || passportFileUrlFromApi != null) + // // Centers the text + // Container( + // color: Colors.white, + // child: Row( + // mainAxisAlignment: MainAxisAlignment.end, + // crossAxisAlignment: CrossAxisAlignment.end, + // children: [ + // GestureDetector( + // onTap: () { + // print('DOWNLOAD - $docUploadedFile'); + // + // if (docUploadedFile != null) { + // try { + // final blob = html.Blob([docUploadedFile!]); + // + // final url = html.Url.createObjectUrlFromBlob(blob); + // + // final anchor = html.AnchorElement(href: url) + // ..setAttribute( + // 'download', + // selectedFileNames ?? "document.pdf", + // ) + // ..click(); + // + // html.Url.revokeObjectUrl(url); + // + // print("Download triggered successfully!"); + // } catch (e) { + // print("Error during download: $e"); + // } + // } else if (passportFileUrlFromApi != null) { + // print("Raw file path: $passportFileUrlFromApi"); + // + // final path = + // 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId'; + // + // apiService.getPdfDownload(path, selectedId); + // } else { + // print("No file available to download."); + // } + // }, + // + // // onTap: () { + // // print('DOWNLOAD - $docUploadedFile'); + // // + // // if (docUploadedFile != null) { + // // try { + // // if (kIsWeb) { + // // // ✅ WEB: use bytes + // // final blob = html.Blob([docUploadedFile!.bytes!]); + // // final url = html.Url.createObjectUrlFromBlob( + // // blob, + // // ); + // // + // // final anchor = html.AnchorElement(href: url) + // // ..setAttribute( + // // 'download', + // // selectedFileNames ?? "document.pdf", + // // ) + // // ..click(); + // // + // // html.Url.revokeObjectUrl(url); + // // print("Download triggered successfully (web)!"); + // // } else { + // // // ✅ MOBILE/DESKTOP: use file path + // // print( + // // "Local file path: ${docUploadedFile!.path}", + // // ); + // // + // // // Example: open the file using open_filex + // // // await OpenFilex.open(docUploadedFile!.path!); + // // } + // // } catch (e) { + // // print("Error during download: $e"); + // // } + // // } else if (passportFileUrlFromApi != null) { + // // print("Raw file path: $passportFileUrlFromApi"); + // // + // // final path = + // // 'api/agent/downloadAgentCertificateFile?agent_id=$selectedId'; + // // + // // apiService.getPdfDownload(path, selectedId); + // // } else { + // // print("No file available to download."); + // // } + // // }, + // child: Container( + // padding: const EdgeInsets.all(5), + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(5), + // color: Colors.green.shade300, + // ), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.end, + // crossAxisAlignment: CrossAxisAlignment.end, + // children: [ + // Text( + // "Download", + // style: TextStyle( + // fontSize: 12, + // fontWeight: FontWeight.w200, + // color: Colors.white, + // ), + // overflow: TextOverflow.ellipsis, + // textAlign: TextAlign + // .end, // Ensures text is centered within the Text widget + // ), + // SizedBox(width: 5), + // Icon(Icons.download, size: 13, color: Colors.white), + // ], + // ), + // ), + // ), + // ], + // ), + // ), + // ], + // ), ], ); } diff --git a/lib/presentation/screens/UserManagement/Agent/agentIncentiveFile.dart b/lib/presentation/screens/UserManagement/Agent/agentIncentiveFile.dart index 077403f..504a14e 100644 --- a/lib/presentation/screens/UserManagement/Agent/agentIncentiveFile.dart +++ b/lib/presentation/screens/UserManagement/Agent/agentIncentiveFile.dart @@ -2,6 +2,7 @@ // import 'dart:nativewrappers/_internal/vm/lib/typed_data_patch.dart'; import 'dart:typed_data'; // Import for Uint8List import 'package:dropdown_search/dropdown_search.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -15,11 +16,12 @@ import '../../../../core/services/api_service.dart'; import '../../../../data/services/auth_service.dart'; import '../../../../data/utils/validators.dart'; import '../../../providers/manager_provider.dart'; +import '../../../themes/indicators/customizd_file_upload.dart'; import '../../../themes/indicators/date_field_theme.dart'; import '../../../themes/indicators/input_field_decoration.dart'; import '../../../themes/indicators/month_field_theme.dart'; import '../../../themes/indicators/search_field_theme.dart'; -import '../../../themes/indicators/upload_doc_theme.dart'; +// import '../../../themes/indicators/upload_doc_theme.dart'; /// function to open the modal void showUploadIncentiveModal(BuildContext context) { @@ -50,7 +52,8 @@ class UploadIncentiveModalState extends ConsumerState { List> filteredIncentiveData = []; Map controllers = {}; - html.File? passportFile; + // html.File? passportFile; + PlatformFile? passportFile; String? selectedFileNames; List tabHeader = ['name', 'agentId', 'date', 'search']; @@ -199,11 +202,12 @@ class UploadIncentiveModalState extends ConsumerState { } Future handleSave() async { + if (!_formKey.currentState!.validate()) return; print("Handl1"); final dataSet = dataDetails(); print("dataSetAgent - $dataSet"); print("Handl13f"); - if (!_formKey.currentState!.validate()) return; + if (passportFile == null) { print("❌ No file selected!"); ScaffoldMessenger.of(context).showSnackBar( @@ -233,35 +237,65 @@ class UploadIncentiveModalState extends ConsumerState { print("USerDAta - $dataSet"); + // dataSet.forEach((key, value) { + // request.fields[key] = value.toString(); + // print("✅ Encoded travel_details2: ${request.fields[key]}"); + // }); + dataSet.forEach((key, value) { - request.fields[key] = value.toString(); - print("✅ Encoded travel_details2: ${request.fields[key]}"); + if (key != 'incentive_file_name') { + request.fields[key] = value.toString(); + print("✅ Encoded $key: ${request.fields[key]}"); + } }); - // Attach file if selected if (passportFile != null) { try { - final reader = html.FileReader(); - reader.readAsArrayBuffer(passportFile!); - await reader.onLoad.first; - - final data = reader.result as Uint8List; - - final multipartFile = http.MultipartFile.fromBytes( - 'incentive_file_name', - data, - filename: passportFile!.name, - ); - - request.files.add(multipartFile); + if (passportFile!.bytes != null) { + final multipartFile = http.MultipartFile.fromBytes( + 'incentive_file_name', + passportFile!.bytes!, + filename: passportFile!.name, + ); + request.files.add(multipartFile); + } else if (passportFile!.path != null) { + final multipartFile = await http.MultipartFile.fromPath( + 'certificate_file_name', + passportFile!.path!, + filename: passportFile!.name, + ); + request.files.add(multipartFile); + } print("📎 File attached: ${passportFile!.name}"); } catch (e) { - print("❌ Failed to read file: $e"); + print("❌ Failed to attach file: $e"); } - } else { - print("⚠️ No passport file selected."); } + // Attach file if selected + // if (passportFile != null) { + // try { + // final reader = html.FileReader(); + // reader.readAsArrayBuffer(passportFile! as html.Blob); + // await reader.onLoad.first; + // + // final data = reader.result as Uint8List; + // + // final multipartFile = http.MultipartFile.fromBytes( + // 'incentive_file_name', + // data, + // filename: passportFile!.name, + // ); + // + // request.files.add(multipartFile); + // print("📎 File attached: ${passportFile!.name}"); + // } catch (e) { + // print("❌ Failed to read file: $e"); + // } + // } else { + // print("⚠️ No passport file selected."); + // } + print("🚀 Sending request with fields: ${request.fields}"); try { @@ -276,7 +310,7 @@ class UploadIncentiveModalState extends ConsumerState { print("📨 Response: ${response.body}"); - final data = dataDetails(); // this is a Map + final data = dataDetails(); final agentId = data["agent_id"]; getAgentIncenctiveFileList(agentId); @@ -492,12 +526,12 @@ class UploadIncentiveModalState extends ConsumerState { // value, // "Upload Document", // ), - validator: (value) { - if (passportFile == null) { - return "Please upload a file"; - } - return null; - }, + // validator: (value) { + // if (passportFile == null) { + // return "Please upload a file"; + // } + // return null; + // }, backgroundColor: Color(0xFFECECEC), hintText: (selectedFileNames == null || @@ -507,9 +541,12 @@ class UploadIncentiveModalState extends ConsumerState { txtwidth: MediaQuery.of(context).size.width * 0.19, onFileSelected: (fileName, file) { - print( - "Picked file: $fileName (${file.size} bytes)", - ); + print("File picked: ${fileName}"); + // print("Size: ${file.size}"); + // print( + // "Path: ${file.path}", + // ); // works on mobile/desktop + // print("Bytes: ${file.bytes}"); setState(() { passportFile = file; selectedFileNames = fileName; diff --git a/lib/presentation/screens/UserManagement/Agent/agentList.dart b/lib/presentation/screens/UserManagement/Agent/agentList.dart index d1a2a0b..4bb0061 100644 --- a/lib/presentation/screens/UserManagement/Agent/agentList.dart +++ b/lib/presentation/screens/UserManagement/Agent/agentList.dart @@ -7,6 +7,7 @@ import '../../../../core/routing/routes.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/utils/Pagination.dart'; import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; import '../../../providers/manager_provider.dart'; import '../../../themes/indicators/export_btn.dart'; import '../../../themes/indicators/filter_btn.dart'; @@ -31,7 +32,7 @@ class AgentListState extends ConsumerState { List> originalData = []; List> filteredData = []; bool isLoading = false; - + dynamic sortedData; @override void initState() { super.initState(); @@ -55,10 +56,23 @@ class AgentListState extends ConsumerState { // } // } + // List get _paginatedData { + // final startIndex = (currentPage - 1) * itemsPerPage; + // final endIndex = (currentPage * itemsPerPage).clamp(0, filteredData.length); + // return filteredData.sublist(startIndex, endIndex); + // } + List get _paginatedData { + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + // Calculate pagination indices final startIndex = (currentPage - 1) * itemsPerPage; - final endIndex = (currentPage * itemsPerPage).clamp(0, filteredData.length); - return filteredData.sublist(startIndex, endIndex); + final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length); + + // Return only the paginated slice + return sortedData.sublist(startIndex, endIndex); } void filterData(String query) { @@ -235,6 +249,9 @@ class AgentListState extends ConsumerState { ExportBtn( sheetName: "Agents", fileName: "agent_list", + txt: !ResponsiveLayout.isMobile(context) + ? true + : false, data: filteredData, headers: [ "id", @@ -278,6 +295,56 @@ class AgentListState extends ConsumerState { ), ), SizedBox(height: 10), + + Container( + height: 50, + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + flex: 1, + child: Text('S.No.', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Agent Name', style: _headerStyle), + ), + Expanded( + flex: 3, + child: Text('Email', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Phone Number', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Id', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Address', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Status', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Action', style: _headerStyle), + ), + ], + ), + ), + Expanded(child: _buildClaimsDataTable(context)), ], ), @@ -321,8 +388,13 @@ class AgentListState extends ConsumerState { ); } - final sortedData = [...filteredData] - ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + // final sortedData = [..._paginatedData] + // ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + final sortedData = [..._paginatedData]; + + // final sortedData = [...filteredData] + // ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); return ListView.builder( // itemCount: filteredData.length + 1, // +1 for header, +1 for pagination @@ -341,25 +413,7 @@ class AgentListState extends ConsumerState { } Widget _buildHeader() { - return Container( - decoration: BoxDecoration( - color: Color(0xFFEDF6F5), - borderRadius: BorderRadius.circular(6), - ), - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), - child: const Row( - children: [ - Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)), - Expanded(flex: 2, child: Text('Agent Name', style: _headerStyle)), - Expanded(flex: 3, child: Text('Email', style: _headerStyle)), - Expanded(flex: 2, child: Text('Phone Number', style: _headerStyle)), - Expanded(flex: 1, child: Text('Id', style: _headerStyle)), - Expanded(flex: 2, child: Text('Address', style: _headerStyle)), - Expanded(flex: 1, child: Text('Status', style: _headerStyle)), - Expanded(flex: 1, child: Text('Action', style: _headerStyle)), - ], - ), - ); + return const SizedBox.shrink(); // empty widget instead of commenting } Widget _buildDataRow(Map item, sno) { @@ -413,7 +467,7 @@ class AgentListState extends ConsumerState { }); final response = apiService.updateStatus( item['id'], - val ? "1" : "0", + val ? "0" : "1", 'agent', ); print("Response - $response"); diff --git a/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart b/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart new file mode 100644 index 0000000..c427fd6 --- /dev/null +++ b/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart @@ -0,0 +1,749 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:jwt_decode/jwt_decode.dart'; + +import '../../../../core/services/api_service.dart'; +import '../../../../data/services/auth_service.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; +import '../../../providers/manager_provider.dart'; + +class Profile extends ConsumerStatefulWidget { + const Profile({super.key}); + + @override + ConsumerState createState() => ProfileState(); +} + +class ProfileState extends ConsumerState { + late ApiService apiService; + + List> filteredIncentiveData = []; + List> getAgentIncentiveFileData = []; + Map? profileData; + + dynamic roleIdRaw; + dynamic roleId; + + bool isProfile = true; + bool isLoading = false; + String? _token; + dynamic latestId; + @override + void initState() { + super.initState(); + apiService = ApiService(); + // getAgentList(); + _initializeToken(); + // Future.microtask(() { + // final id = ref.read(managerIdProvider); + // if (id != null) { + // getAgentList(id); + // + // // api/staff/managerIncentiveFileList?manager_id=1 + // } + // }); + } + + Future _initializeToken() async { + _token = await AuthService.getToken(); + print("profileDataAPISERTOKEN - $_token"); + final Map decodedToken = Jwt.parseJwt(_token!); + setState(() { + profileData = decodedToken['data']; + }); + print('profileDatadecodedTokenProfile : $decodedToken'); + print('profileDatadecodedTokenProfile : $profileData'); + + await getList(); + } + + Future getList() async { + roleIdRaw = profileData?['role_id']; + roleId = roleIdRaw is String ? int.tryParse(roleIdRaw) : roleIdRaw as int?; + + if (roleId == 1) { + final managerIdRaw = profileData?['manager_id']; + final managerId = managerIdRaw is String + ? int.tryParse(managerIdRaw) + : managerIdRaw as int?; + if (managerId != null) { + getIncenctiveFileList(managerId); + } + } else if (roleId != 1 && roleId != 2) { + final agentIdRaw = profileData?['id']; + final agentId = agentIdRaw is String + ? int.tryParse(agentIdRaw) + : agentIdRaw as int?; + if (agentId != null) { + getIncenctiveFileList(agentId); + } + } + } + + Future getIncenctiveFileList(id) async { + // print('getClaimList agentId - $agentId'); + + setState(() { + isLoading = true; + }); + + try { + final response; + + final roleIdRaw = profileData?['role_id']; + final roleId = roleIdRaw is String + ? int.tryParse(roleIdRaw) + : roleIdRaw as int?; + if (roleId == 1) { + response = await apiService.fetchManagerIncentiveList(id); + } else { + response = await apiService.fetchAgentIncentiveList(id); + } + + if (response['status'] == 'success') { + print('AgentIncentive - ${response['data']}'); + setState(() { + getAgentIncentiveFileData = List>.from( + response['data'], + ); + print('API AgentIncentive - $getAgentIncentiveFileData'); + + filteredIncentiveData = List.from(getAgentIncentiveFileData); + print('originalData - $filteredIncentiveData'); + + // Sort descending by created_on + filteredIncentiveData.sort((a, b) { + final dateA = + DateTime.tryParse(a['created_on'].toString()) ?? DateTime(1970); + final dateB = + DateTime.tryParse(b['created_on'].toString()) ?? DateTime(1970); + return dateB.compareTo(dateA); // newest first + }); + + // Get the latest ID (from the first element after sorting) + if (filteredIncentiveData.isNotEmpty) { + latestId = filteredIncentiveData.first['id']; + print("Latest incentive id: $latestId"); + } + + print('sortedData - $filteredIncentiveData'); + }); + } else { + getAgentIncentiveFileData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + @override + Widget build(BuildContext context) { + return MainLayout( + title: 'Profile', + body: ResponsiveLayout.isMobile(context) + ? Container( + padding: const EdgeInsets.all(6), + width: 450, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + isProfile ? '' : 'Incentive Files', + style: _topheaderStyle, + ), + ], + ), + + isProfile + ? Container( + color: Colors.white, + padding: ResponsiveLayout.isMobile(context) + ? EdgeInsets.all(16.0) + : null, + child: isLoading + ? const Center( + child: Text("No incentive files found"), + ) + : Column( + children: [ + const SizedBox(height: 25), + Container( + width: 70, + height: 70, + decoration: BoxDecoration( + color: Color(0xFFD9D9D9), + borderRadius: BorderRadius.circular( + 30.0, + ), + ), + child: Icon( + Icons.person_outline, + size: 50, + color: Colors.black, + ), + ), + const SizedBox(height: 10), + Text( + profileData?['name'] ?? '-', + style: _headerStyle, + ), + Text( + profileData?['emp_id'] ?? '-', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ), + ), + const SizedBox(height: 26), + Row( + children: [ + const Icon( + Icons.phone_outlined, + size: 20, + color: Colors.black, + ), + const SizedBox(width: 8), + Text( + profileData?['mobile'] ?? '-', + style: _dataBold, + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + const Icon( + Icons.email_outlined, + size: 18, + color: Colors.black, + ), + const SizedBox(width: 8), + Text( + profileData?['email'] ?? '-', + style: _dataBold, + ), + ], + ), + const SizedBox(height: 16), + if (profileData?['role_id'] != '1' && + profileData?['role_id'] != '2') ...[ + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + const Icon( + Icons.location_on_outlined, + size: 18, + color: Colors.black, + ), + const SizedBox(width: 8), + + Expanded( + child: Text( + profileData?['address'] ?? '-', + style: _dataBold, + softWrap: true, + ), + ), + ], + ), + const SizedBox(height: 20), + ], + + if (profileData?['role_id'] != 2) ...[ + Container( + padding: const EdgeInsets.all(6), + color: Color(0xffEDF6F5), + child: GestureDetector( + onTap: () { + print("Download - $latestId"); + dynamic path; + + if (roleId == 1) { + path = + 'api/agent/downloadManagerIncentiveFile?id=$latestId'; + } else if (roleId != 1 && + roleId != 2) { + path = + 'api/agent/downloadAgentIncentiveFile?id=$latestId'; + } + apiService.getPdfDownload( + path, + latestId, + ); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Icon(Icons.download), + SizedBox(width: 8), + Text( + "Download Incentive file", + style: _dataSub, + ), + ], + ), + ), + ), + const SizedBox(height: 10), + TextButton( + onPressed: () { + setState(() { + isProfile = false; + }); + }, + child: Text( + "View Previous Files", + style: TextStyle( + color: Color(0xff425B5B), + decoration: TextDecoration + .underline, // 👈 underline + decorationThickness: 1.5, + ), + ), + ), + ], + const SizedBox(height: 16), + ], + ), + ) + : Container( + color: Colors.white, + padding: ResponsiveLayout.isMobile(context) + ? EdgeInsets.all(16.0) + : null, + child: Column( + children: [ + const SizedBox(height: 10), + isLoading + ? const Center( + child: CircularProgressIndicator(), + ) + : filteredIncentiveData.isEmpty + ? const Center( + child: Text("No incentive files found"), + ) + : SizedBox( + height: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.height * + 0.4 + : 450, + child: ListView.builder( + // padding: const EdgeInsets.all(8), + itemCount: filteredIncentiveData.length, + itemBuilder: (context, index) { + final file = + filteredIncentiveData[index]; + + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + ), + child: IncentiveFileRow( + fileName: + file['incentive_file_name'] ?? + "Unknown", + date: + file['incentive_month'] ?? + "-", + onUpload: () { + print("Upload ${file['id']}"); + final selectedId = file['id']; + + dynamic path; + + if (roleId == 1) { + path = + 'api/agent/downloadManagerIncentiveFile?id=$selectedId'; + } else if (roleId != 1 && + roleId != 2) { + path = + 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + } + apiService.getPdfDownload( + path, + selectedId, + ); + }, + ), + ); + }, + ), + ), + ], + ), + ), + ], + ), + ) + : Container( + padding: const EdgeInsets.all(6), + width: 450, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + isProfile ? 'My Profile' : 'Incentive Files', + style: _topheaderStyle, + ), + Spacer(), + Container( + width: 25, + height: 25, + decoration: BoxDecoration( + color: const Color(0xFFF1F1F1), + borderRadius: BorderRadius.circular(10.0), + ), + child: InkWell( + borderRadius: BorderRadius.circular(10.0), + onTap: () { + Navigator.of(context).pop(); // closes the popup + }, + child: const Icon(Icons.close, size: 18), + ), + ), + ], + ), + + isProfile + ? Container( + color: Colors.white, + padding: ResponsiveLayout.isMobile(context) + ? EdgeInsets.all(16.0) + : null, + child: isLoading + ? const Center( + child: Text("No incentive files found"), + ) + : Column( + children: [ + const SizedBox(height: 25), + Container( + width: 70, + height: 70, + decoration: BoxDecoration( + color: Color(0xFFD9D9D9), + borderRadius: BorderRadius.circular( + 30.0, + ), + ), + child: Icon( + Icons.person_outline, + size: 50, + color: Colors.black, + ), + ), + const SizedBox(height: 10), + Text( + profileData?['name'] ?? '-', + style: _headerStyle, + ), + Text( + profileData?['emp_id'] ?? '-', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ), + ), + const SizedBox(height: 26), + Row( + children: [ + const Icon( + Icons.phone_outlined, + size: 20, + color: Colors.black, + ), + const SizedBox(width: 8), + Text( + profileData?['mobile'] ?? '-', + style: _dataBold, + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + const Icon( + Icons.email_outlined, + size: 18, + color: Colors.black, + ), + const SizedBox(width: 8), + Text( + profileData?['email'] ?? '-', + style: _dataBold, + ), + ], + ), + const SizedBox(height: 16), + if (profileData?['role_id'] != '1' && + profileData?['role_id'] != '2') ...[ + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + const Icon( + Icons.location_on_outlined, + size: 18, + color: Colors.black, + ), + const SizedBox(width: 8), + + Expanded( + child: Text( + profileData?['address'] ?? '-', + style: _dataBold, + softWrap: true, + ), + ), + ], + ), + const SizedBox(height: 20), + ], + + if (profileData?['role_id'] != 2) ...[ + Container( + padding: const EdgeInsets.all(6), + color: Color(0xffEDF6F5), + child: GestureDetector( + onTap: () { + print("Download - $latestId"); + dynamic path; + + if (roleId == 1) { + path = + 'api/agent/downloadManagerIncentiveFile?id=$latestId'; + } else if (roleId != 1 && + roleId != 2) { + path = + 'api/agent/downloadAgentIncentiveFile?id=$latestId'; + } + apiService.getPdfDownload( + path, + latestId, + ); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Icon(Icons.download), + SizedBox(width: 8), + Text( + "Download Incentive file", + style: _dataSub, + ), + ], + ), + ), + ), + const SizedBox(height: 10), + TextButton( + onPressed: () { + setState(() { + isProfile = false; + }); + }, + child: Text( + "View Previous Files", + style: TextStyle( + color: Color(0xff425B5B), + decoration: TextDecoration + .underline, // 👈 underline + decorationThickness: 1.5, + ), + ), + ), + ], + const SizedBox(height: 16), + ], + ), + ) + : Container( + color: Colors.white, + padding: ResponsiveLayout.isMobile(context) + ? EdgeInsets.all(16.0) + : null, + child: Column( + children: [ + const SizedBox(height: 10), + isLoading + ? const Center( + child: CircularProgressIndicator(), + ) + : filteredIncentiveData.isEmpty + ? const Center( + child: Text("No incentive files found"), + ) + : SizedBox( + height: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.height * + 0.4 + : 450, + child: ListView.builder( + // padding: const EdgeInsets.all(8), + itemCount: filteredIncentiveData.length, + itemBuilder: (context, index) { + final file = + filteredIncentiveData[index]; + + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + ), + child: IncentiveFileRow( + fileName: + file['incentive_file_name'] ?? + "Unknown", + date: + file['incentive_month'] ?? + "-", + onUpload: () { + print("Upload ${file['id']}"); + final selectedId = file['id']; + + dynamic path; + + if (roleId == 1) { + path = + 'api/agent/downloadManagerIncentiveFile?id=$selectedId'; + } else if (roleId != 1 && + roleId != 2) { + path = + 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + } + apiService.getPdfDownload( + path, + selectedId, + ); + }, + ), + ); + }, + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + static final _dataBold = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF000000), + ); + + static const _headerStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w700, + fontSize: 20, + ); + + static const _topheaderStyle = TextStyle( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 19, + ); +} + +class IncentiveFileRow extends StatelessWidget { + final String fileName; + final String date; + final VoidCallback? onUpload; + // final VoidCallback? onDelete; + + const IncentiveFileRow({ + super.key, + required this.fileName, + required this.date, + this.onUpload, + // this.onDelete, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 7.0), + // margin: const EdgeInsets.only(bottom: 5), // spacing between rows + decoration: BoxDecoration( + // color: Colors.amber.shade50, + border: Border( + bottom: BorderSide(width: 0.6, color: const Color(0xFFE3E3E3)), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + + children: [ + Container( + padding: const EdgeInsets.all(6.0), + decoration: BoxDecoration( + color: const Color(0xFFF4F6F8), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: const Color(0xFFE3E3E3)), + ), + child: const Icon(Icons.file_present, color: Color(0xFF838587)), + ), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text( + fileName, + + style: const TextStyle( + fontWeight: FontWeight.w600, + color: Color(0xFF1D1B20), + ), + overflow: TextOverflow.ellipsis, + softWrap: true, + maxLines: 1, + ), + ), + Text(date, style: const TextStyle(color: Color(0xFF6E6E6E))), + ], + ), + const Spacer(), + GestureDetector( + onTap: onUpload, + child: const Icon( + Icons.file_download_outlined, + color: Color(0xFF6E6E6E), + ), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/screens/UserManagement/Profile/profile_web.dart b/lib/presentation/screens/UserManagement/Profile/profile_web.dart index 7bdf71c..21bf6c2 100644 --- a/lib/presentation/screens/UserManagement/Profile/profile_web.dart +++ b/lib/presentation/screens/UserManagement/Profile/profile_web.dart @@ -48,13 +48,13 @@ class ProfilePopUpState extends ConsumerState { Future _initializeToken() async { _token = await AuthService.getToken(); - print("APISERTOKEN - $_token"); + print("profileDataAPISERTOKEN - $_token"); final Map decodedToken = Jwt.parseJwt(_token!); setState(() { profileData = decodedToken['data']; }); - print('decodedTokenProfile : $decodedToken'); - print('decodedTokenProfile : $profileData'); + print('profileDatadecodedTokenProfile : $decodedToken'); + print('profileDatadecodedTokenProfile : $profileData'); await getList(); } @@ -144,255 +144,244 @@ class ProfilePopUpState extends ConsumerState { @override Widget build(BuildContext context) { - return MainLayout( - title: 'Profile', - body: Container( - // color: Colors.white, - padding: const EdgeInsets.all(6), - width: 450, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (!ResponsiveLayout.isMobile(context)) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - isProfile ? 'My Profile' : 'Incentive Files', - style: _topheaderStyle, - ), - Spacer(), - Container( - width: 25, - height: 25, - decoration: BoxDecoration( - color: const Color(0xFFF1F1F1), - borderRadius: BorderRadius.circular(10.0), - ), - child: InkWell( - borderRadius: BorderRadius.circular(10.0), - onTap: () { - Navigator.of(context).pop(); // closes the popup - }, - child: const Icon(Icons.close, size: 18), - ), - ), - ], + return Container( + padding: const EdgeInsets.all(6), + width: 450, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + isProfile ? 'My Profile' : 'Incentive Files', + style: _topheaderStyle, ), - if (ResponsiveLayout.isMobile(context)) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - isProfile ? '' : 'Incentive Files', - style: _topheaderStyle, - ), - ], + Spacer(), + Container( + width: 25, + height: 25, + decoration: BoxDecoration( + color: const Color(0xFFF1F1F1), + borderRadius: BorderRadius.circular(10.0), + ), + child: InkWell( + borderRadius: BorderRadius.circular(10.0), + onTap: () { + Navigator.of(context).pop(); // closes the popup + }, + child: const Icon(Icons.close, size: 18), + ), ), + ], + ), - isProfile - ? Container( - color: Colors.white, - padding: ResponsiveLayout.isMobile(context) - ? EdgeInsets.all(16.0) - : null, - child: Column( - children: [ - const SizedBox(height: 25), - Container( - width: 70, - height: 70, - decoration: BoxDecoration( - color: Color(0xFFD9D9D9), - borderRadius: BorderRadius.circular(30.0), - ), - child: Icon( - Icons.person_outline, - size: 50, - color: Colors.black, - ), - ), - const SizedBox(height: 10), - Text(profileData?['name'] ?? '-', style: _headerStyle), - Text( - profileData?['emp_id'] ?? '-', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - color: Color(0xFF000000), - ), - ), - const SizedBox(height: 26), - Row( + isProfile + ? Container( + color: Colors.white, + padding: ResponsiveLayout.isMobile(context) + ? EdgeInsets.all(16.0) + : null, + child: isLoading + ? const Center(child: Text("No incentive files found")) + : Column( children: [ - const Icon( - Icons.phone_outlined, - size: 20, - color: Colors.black, - ), - const SizedBox(width: 8), - Text( - profileData?['mobile'] ?? '-', - style: _dataBold, - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - const Icon( - Icons.email_outlined, - size: 18, - color: Colors.black, - ), - const SizedBox(width: 8), - Text( - profileData?['email'] ?? '-', - style: _dataBold, - ), - ], - ), - const SizedBox(height: 16), - if (profileData?['role_id'] != '1' && - profileData?['role_id'] != '2') ...[ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - Icons.location_on_outlined, - size: 18, + const SizedBox(height: 25), + Container( + width: 70, + height: 70, + decoration: BoxDecoration( + color: Color(0xFFD9D9D9), + borderRadius: BorderRadius.circular(30.0), + ), + child: Icon( + Icons.person_outline, + size: 50, color: Colors.black, ), - const SizedBox(width: 8), - - Expanded( - child: Text( - profileData?['address'] ?? '-', - style: _dataBold, - softWrap: true, - ), + ), + const SizedBox(height: 10), + Text( + profileData?['name'] ?? '-', + style: _headerStyle, + ), + Text( + profileData?['emp_id'] ?? '-', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w400, + color: Color(0xFF000000), ), - ], - ), - const SizedBox(height: 20), - ], - - if (profileData?['role_id'] != 2) ...[ - Container( - padding: const EdgeInsets.all(6), - color: Color(0xffEDF6F5), - child: GestureDetector( - onTap: () { - print("Download - $latestId"); - dynamic path; - - if (roleId == 1) { - path = - 'api/agent/downloadManagerIncentiveFile?id=$latestId'; - } else if (roleId != 1 && roleId != 2) { - path = - 'api/agent/downloadAgentIncentiveFile?id=$latestId'; - } - apiService.getPdfDownload(path, latestId); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + ), + const SizedBox(height: 26), + Row( + children: [ + const Icon( + Icons.phone_outlined, + size: 20, + color: Colors.black, + ), + const SizedBox(width: 8), + Text( + profileData?['mobile'] ?? '-', + style: _dataBold, + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + const Icon( + Icons.email_outlined, + size: 18, + color: Colors.black, + ), + const SizedBox(width: 8), + Text( + profileData?['email'] ?? '-', + style: _dataBold, + ), + ], + ), + const SizedBox(height: 16), + if (profileData?['role_id'] != '1' && + profileData?['role_id'] != '2') ...[ + Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Icon(Icons.download), - SizedBox(width: 8), - Text( - "Download Incentive file", - style: _dataSub, + const Icon( + Icons.location_on_outlined, + size: 18, + color: Colors.black, + ), + const SizedBox(width: 8), + + Expanded( + child: Text( + profileData?['address'] ?? '-', + style: _dataBold, + softWrap: true, + ), ), ], ), - ), - ), - const SizedBox(height: 10), - TextButton( - onPressed: () { - setState(() { - isProfile = false; - }); - }, - child: Text( - "View Previous Files", - style: TextStyle( - color: Color(0xff425B5B), - decoration: - TextDecoration.underline, // 👈 underline - decorationThickness: 1.5, - ), - ), - ), - ], - const SizedBox(height: 16), - ], - ), - ) - : Container( - color: Colors.white, - padding: ResponsiveLayout.isMobile(context) - ? EdgeInsets.all(16.0) - : null, - child: Column( - children: [ - const SizedBox(height: 10), - isLoading - ? const Center(child: CircularProgressIndicator()) - : filteredIncentiveData.isEmpty - ? const Center( - child: Text("No incentive files found"), - ) - : SizedBox( - height: ResponsiveLayout.isMobile(context) - ? MediaQuery.of(context).size.height * 0.4 - : 450, - child: ListView.builder( - // padding: const EdgeInsets.all(8), - itemCount: filteredIncentiveData.length, - itemBuilder: (context, index) { - final file = filteredIncentiveData[index]; + const SizedBox(height: 20), + ], - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - ), - child: IncentiveFileRow( - fileName: - file['incentive_file_name'] ?? - "Unknown", - date: file['incentive_month'] ?? "-", - onUpload: () { - print("Upload ${file['id']}"); - final selectedId = file['id']; + if (profileData?['role_id'] != 2) ...[ + Container( + padding: const EdgeInsets.all(6), + color: Color(0xffEDF6F5), + child: GestureDetector( + onTap: () { + print("Download - $latestId"); + dynamic path; - dynamic path; - - if (roleId == 1) { - path = - 'api/agent/downloadManagerIncentiveFile?id=$selectedId'; - } else if (roleId != 1 && - roleId != 2) { - path = - 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; - } - apiService.getPdfDownload( - path, - selectedId, - ); - }, - ), - ); + if (roleId == 1) { + path = + 'api/agent/downloadManagerIncentiveFile?id=$latestId'; + } else if (roleId != 1 && roleId != 2) { + path = + 'api/agent/downloadAgentIncentiveFile?id=$latestId'; + } + apiService.getPdfDownload(path, latestId); }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.download), + SizedBox(width: 8), + Text( + "Download Incentive file", + style: _dataSub, + ), + ], + ), ), ), - ], - ), + const SizedBox(height: 10), + TextButton( + onPressed: () { + setState(() { + isProfile = false; + }); + }, + child: Text( + "View Previous Files", + style: TextStyle( + color: Color(0xff425B5B), + decoration: TextDecoration + .underline, // 👈 underline + decorationThickness: 1.5, + ), + ), + ), + ], + const SizedBox(height: 16), + ], + ), + ) + : Container( + color: Colors.white, + padding: ResponsiveLayout.isMobile(context) + ? EdgeInsets.all(16.0) + : null, + child: Column( + children: [ + const SizedBox(height: 10), + isLoading + ? const Center(child: CircularProgressIndicator()) + : filteredIncentiveData.isEmpty + ? const Center( + child: Text("No incentive files found"), + ) + : SizedBox( + height: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.height * 0.4 + : 450, + child: ListView.builder( + // padding: const EdgeInsets.all(8), + itemCount: filteredIncentiveData.length, + itemBuilder: (context, index) { + final file = filteredIncentiveData[index]; + + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + ), + child: IncentiveFileRow( + fileName: + file['incentive_file_name'] ?? + "Unknown", + date: file['incentive_month'] ?? "-", + onUpload: () { + print("Upload ${file['id']}"); + final selectedId = file['id']; + + dynamic path; + + if (roleId == 1) { + path = + 'api/agent/downloadManagerIncentiveFile?id=$selectedId'; + } else if (roleId != 1 && roleId != 2) { + path = + 'api/agent/downloadAgentIncentiveFile?id=$selectedId'; + } + apiService.getPdfDownload( + path, + selectedId, + ); + }, + ), + ); + }, + ), + ), + ], ), - ], - ), + ), + ], ), ); } diff --git a/lib/presentation/screens/UserManagement/Staff/staff.dart b/lib/presentation/screens/UserManagement/Staff/staff.dart index 2de395d..dfebc43 100644 --- a/lib/presentation/screens/UserManagement/Staff/staff.dart +++ b/lib/presentation/screens/UserManagement/Staff/staff.dart @@ -12,13 +12,10 @@ import 'package:nhance_partner/presentation/themes/indicators/text_field_theme.d import '../../../../core/config/env.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/services/auth_service.dart'; -import '../../../../data/utils/Pagination.dart'; import '../../../../data/utils/validators.dart'; import '../../../layouts/main_layout.dart'; import '../../../providers/manager_provider.dart'; -import '../../../themes/indicators/export_btn.dart'; -import '../../../themes/indicators/search_field_theme.dart'; -import '../../../themes/indicators/upload_doc_theme.dart'; + import 'package:universal_html/html.dart' as html; class Staff extends ConsumerStatefulWidget { diff --git a/lib/presentation/screens/UserManagement/Staff/staffList.dart b/lib/presentation/screens/UserManagement/Staff/staffList.dart index b97a014..ebe2689 100644 --- a/lib/presentation/screens/UserManagement/Staff/staffList.dart +++ b/lib/presentation/screens/UserManagement/Staff/staffList.dart @@ -7,6 +7,7 @@ import '../../../../core/routing/routes.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/utils/Pagination.dart'; import '../../../layouts/main_layout.dart'; +import '../../../layouts/responsive_layout.dart'; import '../../../providers/manager_provider.dart'; import '../../../themes/indicators/export_btn.dart'; import '../../../themes/indicators/filter_btn.dart'; @@ -56,9 +57,14 @@ class StaffListState extends ConsumerState { // } List get _paginatedData { + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + final startIndex = (currentPage - 1) * itemsPerPage; - final endIndex = (currentPage * itemsPerPage).clamp(0, filteredData.length); - return filteredData.sublist(startIndex, endIndex); + final endIndex = (currentPage * itemsPerPage).clamp(0, sortedData.length); + + return sortedData.sublist(startIndex, endIndex); } void filterData(String query) { @@ -210,6 +216,9 @@ class StaffListState extends ConsumerState { ExportBtn( sheetName: "Staff", fileName: "staff_list", + txt: !ResponsiveLayout.isMobile(context) + ? true + : false, data: filteredData, headers: [ "id", @@ -253,6 +262,48 @@ class StaffListState extends ConsumerState { ), ), SizedBox(height: 10), + Container( + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 16, + ), + child: const Row( + children: [ + Expanded( + flex: 1, + child: Text('S.No.', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Staff Name', style: _headerStyle), + ), + Expanded( + flex: 3, + child: Text('Email', style: _headerStyle), + ), + Expanded( + flex: 2, + child: Text('Phone Number', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Employee Id', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Status', style: _headerStyle), + ), + Expanded( + flex: 1, + child: Text('Action', style: _headerStyle), + ), + ], + ), + ), Expanded(child: _buildDataTable(context)), ], ), @@ -296,8 +347,7 @@ class StaffListState extends ConsumerState { ); } - final sortedData = [...filteredData] - ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + final sortedData = [..._paginatedData]; return ListView.builder( // itemCount: filteredData.length + 1, // +1 for header, +1 for pagination @@ -316,24 +366,7 @@ class StaffListState extends ConsumerState { } Widget _buildHeader() { - return Container( - decoration: BoxDecoration( - color: Color(0xFFEDF6F5), - borderRadius: BorderRadius.circular(6), - ), - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), - child: const Row( - children: [ - Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)), - Expanded(flex: 2, child: Text('Staff Name', style: _headerStyle)), - Expanded(flex: 3, child: Text('Email', style: _headerStyle)), - Expanded(flex: 2, child: Text('Phone Number', style: _headerStyle)), - Expanded(flex: 1, child: Text('Employee Id', style: _headerStyle)), - Expanded(flex: 1, child: Text('Status', style: _headerStyle)), - Expanded(flex: 1, child: Text('Action', style: _headerStyle)), - ], - ), - ); + return SizedBox.shrink(); } Widget _buildDataRow(Map item, sno) { @@ -381,7 +414,7 @@ class StaffListState extends ConsumerState { }); final response = apiService.updateStatus( item['id'], - val ? "1" : "0", + val ? "0" : "1", 'staff', ); print("Response - $response"); diff --git a/lib/presentation/themes/indicators/customizd_file_upload.dart b/lib/presentation/themes/indicators/customizd_file_upload.dart new file mode 100644 index 0000000..6e20395 --- /dev/null +++ b/lib/presentation/themes/indicators/customizd_file_upload.dart @@ -0,0 +1,215 @@ +import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; + +import 'fileUploadService.dart'; + +// class ThemedUploadField extends FormField { +// ThemedUploadField({ +// Key? key, +// String? hintText, +// double? txtwidth, +// double? txtheight, +// Color? backgroundColor, +// Color? borderColor, +// Color? errorBorderColor, +// FormFieldValidator? validator, +// void Function(String fileName, PlatformFile file)? onFileSelected, +// }) : super( +// key: key, +// validator: validator, +// builder: (FormFieldState state) { +// final fileService = FileUploadService(); +// String? selectedFileName; +// +// Future _pickFile(BuildContext context) async { +// final error = await fileService.pickSingleFile(maxFileSizeInMB: 3); +// if (error != null) { +// ScaffoldMessenger.of( +// context, +// ).showSnackBar(SnackBar(content: Text(error))); +// state.didChange(null); // mark invalid +// } else if (fileService.singleFile != null) { +// selectedFileName = fileService.singleFile!.name; +// state.didChange(selectedFileName); // update form value +// +// onFileSelected?.call( +// fileService.singleFile!.name, +// fileService.singleFile!, +// ); +// } +// } +// +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// width: txtwidth ?? MediaQuery.of(state.context).size.width, +// height: txtheight, +// child: InkWell( +// onTap: () => _pickFile(state.context), +// child: Container( +// padding: const EdgeInsets.symmetric( +// vertical: 10, +// horizontal: 15, +// ), +// decoration: BoxDecoration( +// color: backgroundColor ?? Colors.white, +// borderRadius: BorderRadius.circular(10), +// border: Border.all( +// color: state.hasError +// ? (errorBorderColor ?? Colors.red) +// : (borderColor ?? Colors.grey.shade50), +// ), +// ), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Expanded( +// child: Text( +// selectedFileName ?? hintText ?? "Upload Document", +// style: TextStyle( +// fontSize: 12, +// color: state.hasError +// ? Colors.red +// : Colors.black, +// ), +// overflow: TextOverflow.ellipsis, +// ), +// ), +// const Icon( +// Icons.file_upload_outlined, +// color: Colors.black, +// ), +// ], +// ), +// ), +// ), +// ), +// if (state.hasError) +// Padding( +// padding: const EdgeInsets.only(left: 8, top: 4), +// child: Text( +// state.errorText ?? "", +// style: const TextStyle(color: Colors.red, fontSize: 10), +// ), +// ), +// ], +// ); +// }, +// ); +// } + +class ThemedUploadField extends StatefulWidget { + final String? hintText; + final double? txtwidth; + final double? txtheight; + final Color? backgroundColor; + final Color? borderColor; + final Color? errorBorderColor; + final Function(String fileName, PlatformFile file)? onFileSelected; + FormFieldValidator? validator; + + ThemedUploadField({ + super.key, + this.hintText, + this.txtwidth, + this.txtheight, + this.backgroundColor, + this.borderColor, + this.errorBorderColor, + this.onFileSelected, + this.validator, + }); + + @override + State createState() => _ThemedUploadFieldState(); +} + +class _ThemedUploadFieldState extends State { + final fileService = FileUploadService(); + String? selectedFileName; + String? errorMessage; + + Future _pickFile() async { + final error = await fileService.pickSingleFile(maxFileSizeInMB: 3); + if (error != null) { + setState(() => errorMessage = error); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(error))); + } else if (fileService.singleFile != null) { + setState(() { + selectedFileName = fileService.singleFile!.name; + errorMessage = null; + }); + + widget.onFileSelected?.call( + fileService.singleFile!.name, + fileService.singleFile!, + ); + } + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: widget.txtwidth ?? MediaQuery.of(context).size.width, + height: widget.txtheight, + child: DecoratedBox( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10)), + child: InkWell( + onTap: _pickFile, + borderRadius: BorderRadius.circular(10), + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 15, + ), + decoration: BoxDecoration( + color: widget.backgroundColor ?? Colors.white, + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: errorMessage != null + ? (widget.errorBorderColor ?? Colors.red) + : (widget.borderColor ?? Colors.grey.shade50), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + selectedFileName ?? + widget.hintText ?? + "Upload Document", + style: TextStyle( + fontSize: 12, + color: errorMessage != null + ? Colors.red + : Colors.black, + ), + overflow: TextOverflow.ellipsis, + ), + ), + const Icon(Icons.file_upload_outlined, color: Colors.black), + ], + ), + ), + ), + ), + ), + if (errorMessage != null) + Padding( + padding: const EdgeInsets.only(left: 8, top: 4), + child: Text( + errorMessage!, + style: const TextStyle(color: Colors.red, fontSize: 10), + ), + ), + ], + ); + } +} diff --git a/lib/presentation/themes/indicators/export_btn.dart b/lib/presentation/themes/indicators/export_btn.dart index f7d48df..a3322ab 100644 --- a/lib/presentation/themes/indicators/export_btn.dart +++ b/lib/presentation/themes/indicators/export_btn.dart @@ -21,9 +21,10 @@ class ExportBtn extends HookWidget { final String fileName; final List> data; final List headers; // dynamic headers - + final bool? txt; const ExportBtn({ super.key, + this.txt, required this.sheetName, required this.fileName, required this.data, @@ -50,15 +51,17 @@ class ExportBtn extends HookWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - const Text( - 'Export', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14, - ), - ), - const SizedBox(width: 20), + ?txt! + ? Text( + 'Export', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ) + : null, + ?txt! ? SizedBox(width: 20) : null, Icon(Icons.input_sharp, color: Colors.white), // Image.asset("assets/miscellaneous/export", height: 15, width: 15), ], diff --git a/lib/presentation/themes/indicators/fileUploadService.dart b/lib/presentation/themes/indicators/fileUploadService.dart new file mode 100644 index 0000000..5b420c0 --- /dev/null +++ b/lib/presentation/themes/indicators/fileUploadService.dart @@ -0,0 +1,40 @@ +import 'package:file_picker/file_picker.dart'; + +class FileUploadService { + FileUploadService._(); + static final FileUploadService _instance = FileUploadService._(); + factory FileUploadService() => _instance; + + PlatformFile? singleFile; + + static const allowedExtensions = ['pdf', 'png', 'jpg', 'jpeg']; + + Future pickSingleFile({int maxFileSizeInMB = 5}) async { + final result = await FilePicker.platform.pickFiles( + allowMultiple: false, + withData: true, + type: FileType.custom, + allowedExtensions: allowedExtensions, + ); + + if (result != null && result.files.isNotEmpty) { + final file = result.files.first; + final ext = file.extension?.toLowerCase() ?? ''; + final sizeInMB = file.size / (1024 * 1024); + + if (!allowedExtensions.contains(ext)) { + return "Unsupported format: ${file.name}"; + } + if (sizeInMB > maxFileSizeInMB) { + return "File too large (${file.name}). Max $maxFileSizeInMB MB allowed."; + } + + singleFile = file; + } + return null; // success + } + + void clearSingle() { + singleFile = null; + } +} diff --git a/lib/presentation/themes/indicators/outlineWidget b/lib/presentation/themes/indicators/outlineWidget new file mode 100644 index 0000000..d3fe123 --- /dev/null +++ b/lib/presentation/themes/indicators/outlineWidget @@ -0,0 +1,147 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../../../../data/utils/Pagination.dart'; +import '../../../layouts/main_layout.dart'; +import '../../../themes/indicators/export_btn.dart'; +import '../../../themes/indicators/search_field_theme.dart'; + +class SampleList extends StatefulWidget { + const SampleList({super.key}); + @override + AgentListState createState() => AgentListState(); +} + +class SampleListState extends State { + int currentPage = 0; + int itemsPerPage = 10; + + List> dataVal = []; + + final TextEditingController _searchController = TextEditingController(); + @override + Widget build(BuildContext context) { + return MainLayout( + title: "Agent", + body: Container( + // color: Colors.yellow.shade50, + width: MediaQuery.of(context).size.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + // height: 30, + // color: Colors.red.shade50, + width: MediaQuery.of(context).size.width, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Icon( + Icons.arrow_left_sharp, + size: 35, + color: Color(0xFF425B5B), + ), + Text( + "Agent", + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + ), + ], + ), + ), + + SizedBox(height: 10), + Expanded( + child: Container( + // color: Colors.green, + color: Colors.green.shade50, + width: MediaQuery.of(context).size.width, + + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Container( + // height: 40, + // color: Colors.pink, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + ThemedSearchField( + hintText: 'Search', + backgroundColor: Color(0xFFF6F8F8), + controller: _searchController, + txtwidth: MediaQuery.of(context).size.width * 0.2, + ), + Text("Home Page Content 2"), + + Spacer(), + + ExportBtn(), + SizedBox(width: 10), + GestureDetector( + onTap: () { + print('Export'); + }, + child: Container( + padding: EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: Color(0xFF425B5B), + borderRadius: BorderRadius.circular(8.0), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.add, color: Colors.white), + + SizedBox(width: 10), + + Text( + 'Create New Agent', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + + Container( + // height: 20, + width: MediaQuery.of(context).size.width, + // color: Colors.green.shade50, + child: PaginationControls( + currentPage: currentPage, + itemsPerPage: itemsPerPage, + totalItems: dataVal.length, + // activeColor: layoutColor, // your theme color + onPageChanged: (page) { + setState(() { + currentPage = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage = items; + currentPage = 0; + }); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/themes/indicators/singleFileUpload.dart b/lib/presentation/themes/indicators/singleFileUpload.dart new file mode 100644 index 0000000..129f6be --- /dev/null +++ b/lib/presentation/themes/indicators/singleFileUpload.dart @@ -0,0 +1,70 @@ +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; + +class SingleFileUploadWidget extends StatefulWidget { + const SingleFileUploadWidget({super.key}); + + @override + State createState() => SingleFileUploadWidgetState(); +} + +class SingleFileUploadWidgetState extends State { + PlatformFile? selectedFile; + + Future pickFile() async { + final result = await FilePicker.platform.pickFiles( + allowMultiple: false, + withData: true, + type: FileType.custom, + allowedExtensions: ['pdf', 'png', 'jpg', 'jpeg', 'heic'], + ); + + if (result != null && result.files.isNotEmpty) { + setState(() { + selectedFile = result.files.first; + }); + } + } + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: pickFile, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE26728)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + selectedFile != null ? selectedFile!.name : "Upload Document", + style: const TextStyle( + fontSize: 14, + color: Colors.black, + overflow: TextOverflow.ellipsis, + ), + ), + ), + const Icon( + Icons.file_upload_outlined, + color: Color(0xFFE26728), + size: 22, + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/themes/indicators/upload_doc_theme.dart b/lib/presentation/themes/indicators/upload_doc_theme.dart index f12fa9b..62e72c7 100644 --- a/lib/presentation/themes/indicators/upload_doc_theme.dart +++ b/lib/presentation/themes/indicators/upload_doc_theme.dart @@ -1,157 +1,204 @@ -import 'dart:html' as html; -import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class ThemedUploadField extends FormField { - ThemedUploadField({ - super.key, - String? hintText, - double? txtwidth, - double? txtheight, - Color? backgroundColor, - Color? borderColor, - Color? errorBorderColor, - FormFieldValidator? validator, - Function(String fileName, dynamic file)? onFileSelected, - }) : super( - validator: validator, - builder: (FormFieldState state) { - return _ThemedUploadFieldBody( - hintText: hintText, - txtwidth: txtwidth, - txtheight: txtheight, - backgroundColor: backgroundColor, - borderColor: borderColor, - errorBorderColor: errorBorderColor, - onFileSelected: (fileName, file) { - state.didChange(fileName); // update validation state - onFileSelected?.call(fileName, file); - }, - errorText: state.errorText, - ); - }, - ); -} - -class _ThemedUploadFieldBody extends StatefulWidget { - const _ThemedUploadFieldBody({ - this.hintText, - this.txtwidth, - this.txtheight, - this.backgroundColor, - this.borderColor, - this.errorBorderColor, - this.onFileSelected, - this.errorText, - }); - - final String? hintText; - final double? txtwidth; - final double? txtheight; - final Color? backgroundColor; - final Color? borderColor; - final Color? errorBorderColor; - final Function(String fileName, dynamic file)? onFileSelected; - final String? errorText; - - @override - State<_ThemedUploadFieldBody> createState() => _ThemedUploadFieldBodyState(); -} - -class _ThemedUploadFieldBodyState extends State<_ThemedUploadFieldBody> { - String? selectedFileName; - - void pickPDFWeb() { - final uploadInput = html.FileUploadInputElement(); - uploadInput.accept = '.pdf'; - uploadInput.click(); - - uploadInput.onChange.listen((e) { - final file = uploadInput.files!.first; - - // Ensure PDF type - if (!file.type.contains("pdf")) { - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text("Only PDF files allowed"))); - return; - } - - // Size check (3 MB) - const maxFileSize = 3 * 1024 * 1024; - if (file.size > maxFileSize) { - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text("File exceeds 3MB"))); - return; - } - - setState(() => selectedFileName = file.name); - widget.onFileSelected?.call(file.name, file); - }); - } - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: widget.txtwidth ?? MediaQuery.of(context).size.width, - height: widget.txtheight, - child: DecoratedBox( - decoration: BoxDecoration(borderRadius: BorderRadius.circular(10)), - child: InkWell( - onTap: pickPDFWeb, - borderRadius: BorderRadius.circular(10), - child: Container( - padding: const EdgeInsets.symmetric( - vertical: 10, - horizontal: 15, - ), - decoration: BoxDecoration( - color: widget.backgroundColor ?? Colors.white, - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: widget.errorText != null - ? (widget.errorBorderColor ?? Colors.red) - : (widget.borderColor ?? Colors.grey.shade50), - width: 1, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - selectedFileName ?? - widget.hintText ?? - "Upload Documents", - style: TextStyle( - fontSize: 12, - color: widget.errorText != null - ? Colors.red - : Colors.black, - ), - overflow: TextOverflow.ellipsis, - ), - ), - const Icon(Icons.file_upload_outlined, color: Colors.black), - ], - ), - ), - ), - ), - ), - // if (widget.errorText != null) - // Padding( - // padding: const EdgeInsets.only(left: 8, top: 4), - // child: Text( - // widget.errorText!, - // style: const TextStyle(color: Colors.red, fontSize: 10), - // ), - // ), - ], - ); - } -} +// import 'dart:html' as html; +// import 'package:file_picker/file_picker.dart'; +// import 'package:flutter/foundation.dart'; +// import 'package:flutter/material.dart'; +// import 'package:google_fonts/google_fonts.dart'; +// import 'package:http/http.dart' as http; +// +// import 'package:flutter/material.dart'; +// import 'package:file_picker/file_picker.dart'; +// import 'package:http/http.dart' as http; +// import 'package:http_parser/http_parser.dart'; +// import 'package:flutter/foundation.dart' show kIsWeb; +// +// class ThemedUploadField extends FormField { +// ThemedUploadField({ +// super.key, +// String? hintText, +// double? txtwidth, +// double? txtheight, +// Color? backgroundColor, +// Color? borderColor, +// Color? errorBorderColor, +// FormFieldValidator? validator, +// Function(String fileName, dynamic file)? onFileSelected, +// }) : super( +// validator: validator, +// builder: (FormFieldState state) { +// return _ThemedUploadFieldBody( +// hintText: hintText, +// txtwidth: txtwidth, +// txtheight: txtheight, +// backgroundColor: backgroundColor, +// borderColor: borderColor, +// errorBorderColor: errorBorderColor, +// onFileSelected: (fileName, file) { +// state.didChange(fileName); // update validation state +// onFileSelected?.call(fileName, file); +// }, +// errorText: state.errorText, +// ); +// }, +// ); +// } +// +// class _ThemedUploadFieldBody extends StatefulWidget { +// const _ThemedUploadFieldBody({ +// this.hintText, +// this.txtwidth, +// this.txtheight, +// this.backgroundColor, +// this.borderColor, +// this.errorBorderColor, +// this.onFileSelected, +// this.errorText, +// }); +// +// final String? hintText; +// final double? txtwidth; +// final double? txtheight; +// final Color? backgroundColor; +// final Color? borderColor; +// final Color? errorBorderColor; +// final Function(String fileName, dynamic file)? onFileSelected; +// final String? errorText; +// +// @override +// State<_ThemedUploadFieldBody> createState() => _ThemedUploadFieldBodyState(); +// } +// +// class _ThemedUploadFieldBodyState extends State<_ThemedUploadFieldBody> { +// String? selectedFileName; +// +// // void pickPDFWeb() { +// // final uploadInput = html.FileUploadInputElement(); +// // uploadInput.accept = '.pdf'; +// // uploadInput.click(); +// // +// // uploadInput.onChange.listen((e) { +// // final file = uploadInput.files!.first; +// // +// // // Ensure PDF type +// // if (!file.type.contains("pdf")) { +// // ScaffoldMessenger.of( +// // context, +// // ).showSnackBar(SnackBar(content: Text("Only PDF files allowed"))); +// // return; +// // } +// // +// // // Size check (3 MB) +// // const maxFileSize = 3 * 1024 * 1024; +// // if (file.size > maxFileSize) { +// // ScaffoldMessenger.of( +// // context, +// // ).showSnackBar(SnackBar(content: Text("File exceeds 3MB"))); +// // return; +// // } +// // +// // setState(() => selectedFileName = file.name); +// // widget.onFileSelected?.call(file.name, file); +// // }); +// // } +// +// Future pickPDF() async { +// try { +// final result = await FilePicker.platform.pickFiles( +// type: FileType.custom, +// allowedExtensions: ['pdf'], +// withData: true, +// ); +// +// if (result != null && result.files.isNotEmpty) { +// final file = result.files.first; // PlatformFile +// +// if (file.extension?.toLowerCase() != "pdf") { +// ScaffoldMessenger.of(context).showSnackBar( +// const SnackBar(content: Text("Only PDF files allowed")), +// ); +// return; +// } +// +// if (file.size > 3 * 1024 * 1024) { +// ScaffoldMessenger.of( +// context, +// ).showSnackBar(const SnackBar(content: Text("File exceeds 3MB"))); +// return; +// } +// +// setState(() => selectedFileName = file.name); +// +// // Always pass PlatformFile +// widget.onFileSelected?.call(file.name, file); +// } +// } catch (e, st) { +// debugPrint("File picker error: $e\n$st"); // 👈 safer logging +// // ScaffoldMessenger.of( +// // context, +// // ).showSnackBar(const SnackBar(content: Text("Error picking file"))); +// } +// } +// +// @override +// Widget build(BuildContext context) { +// return Column( +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Container( +// width: widget.txtwidth ?? MediaQuery.of(context).size.width, +// height: widget.txtheight, +// child: DecoratedBox( +// decoration: BoxDecoration(borderRadius: BorderRadius.circular(10)), +// child: InkWell( +// onTap: pickPDF, +// borderRadius: BorderRadius.circular(10), +// child: Container( +// padding: const EdgeInsets.symmetric( +// vertical: 10, +// horizontal: 15, +// ), +// decoration: BoxDecoration( +// color: widget.backgroundColor ?? Colors.white, +// borderRadius: BorderRadius.circular(10), +// border: Border.all( +// color: widget.errorText != null +// ? (widget.errorBorderColor ?? Colors.red) +// : (widget.borderColor ?? Colors.grey.shade50), +// width: 1, +// ), +// ), +// child: Row( +// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// children: [ +// Expanded( +// child: Text( +// selectedFileName ?? +// widget.hintText ?? +// "Upload Documents", +// style: TextStyle( +// fontSize: 12, +// color: widget.errorText != null +// ? Colors.red +// : Colors.black, +// ), +// overflow: TextOverflow.ellipsis, +// ), +// ), +// const Icon(Icons.file_upload_outlined, color: Colors.black), +// ], +// ), +// ), +// ), +// ), +// ), +// // if (widget.errorText != null) +// // Padding( +// // padding: const EdgeInsets.only(left: 8, top: 4), +// // child: Text( +// // widget.errorText!, +// // style: const TextStyle(color: Colors.red, fontSize: 10), +// // ), +// // ), +// ], +// ); +// } +// } diff --git a/lib/presentation/widgets/drawer_menu.dart b/lib/presentation/widgets/drawer_menu.dart index 6317cc7..219e6b5 100644 --- a/lib/presentation/widgets/drawer_menu.dart +++ b/lib/presentation/widgets/drawer_menu.dart @@ -72,7 +72,7 @@ class DrawerMenuState extends ConsumerState { if (key == 'Reports') ...[ GestureDetector( onTap: () { - print("Tappped Agent"); + context.go(AppRoutes.enquiryLst); }, child: const Text( "Enquiries", @@ -175,7 +175,9 @@ class DrawerMenuState extends ConsumerState { DrawerContentWrapper( child: IconButton( - onPressed: () {}, + onPressed: () { + context.go(AppRoutes.tabEnquiry); + }, icon: Icon(Icons.list_alt_rounded, size: 30, color: Colors.black), ), ), diff --git a/lib/presentation/widgets/mobile_tabs.dart b/lib/presentation/widgets/mobile_tabs.dart index 7771b60..6ec99c9 100644 --- a/lib/presentation/widgets/mobile_tabs.dart +++ b/lib/presentation/widgets/mobile_tabs.dart @@ -20,9 +20,12 @@ class _MobileTabsState extends State { widget.onTabChanged(index); }, items: const [ - BottomNavigationBarItem(icon: Icon(Icons.home), label: "Home"), + BottomNavigationBarItem(icon: Icon(Icons.dashboard), label: "Home"), BottomNavigationBarItem(icon: Icon(Icons.person), label: "Profile"), - BottomNavigationBarItem(icon: Icon(Icons.settings), label: "Settings"), + BottomNavigationBarItem( + icon: Icon(Icons.event_note_sharp), + label: "Enquiry", + ), ], ); } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 2f0a81b..3eb8669 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,6 +6,7 @@ import FlutterMacOS import Foundation import connectivity_plus +import file_picker import firebase_app_check import firebase_auth import firebase_core @@ -21,6 +22,7 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) diff --git a/pubspec.lock b/pubspec.lock index e477045..c144f10 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" crypto: dependency: transitive description: @@ -297,6 +305,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22 + url: "https://pub.dev" + source: hosted + version: "10.3.2" firebase_app_check: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 7b77608..9bc0d61 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -67,6 +67,7 @@ dependencies: open_file: ^3.5.10 excel: ^4.0.6 dropdown_search: ^6.0.2 + file_picker: ^10.3.2 dev_dependencies: flutter_test: