From 659dba0f143a5752dc8bccdd474a191383a4aa6a Mon Sep 17 00:00:00 2001 From: venbaittech Date: Thu, 16 Oct 2025 15:49:04 +0530 Subject: [PATCH] UI_STAFF_ATTENDANCE --- .flutter-plugins-dependencies | 2 +- lib/core/routing/app_router.dart | 11 + lib/core/routing/routes.dart | 2 + lib/core/services/api_service.dart | 49 ++ lib/main.dart | 19 + lib/presentation/layouts/main_layout.dart | 4 +- .../providers/manager_provider.dart | 6 + .../StaffAttendance/attendanceAllDetails.dart | 662 ++++++++++++++++++ .../individual_Attendance.dart | 602 ++++++++++++++++ .../Profile/profile_mobile.dart | 27 +- .../UserManagement/Profile/profile_web.dart | 23 +- .../widgets/custom_month_filter.dart | 113 +++ lib/presentation/widgets/drawer_menu.dart | 48 +- lib/presentation/widgets/mobile_tabs.dart | 35 +- 14 files changed, 1563 insertions(+), 40 deletions(-) create mode 100644 lib/presentation/screens/StaffAttendance/attendanceAllDetails.dart create mode 100644 lib/presentation/screens/StaffAttendance/individual_Attendance.dart create mode 100644 lib/presentation/widgets/custom_month_filter.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 645115d..3b13433 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.1.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_ios-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.30/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_android-7.0.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_android","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_android-1.0.52/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"open_file_android","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_android-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_android-2.2.18/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.20/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.1.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_mac","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_mac-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_linux-0.0.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_windows-1.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_windows-0.0.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","dependencies":[],"dev_dependency":false},{"name":"firebase_app_check_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check_web-0.2.0+16/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_auth_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth_web-6.0.2/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core_web-3.1.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.0.1/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"flutter_secure_storage_web","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"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-10-10 13:11:50.661744","version":"3.32.1","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.1.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_ios-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.30/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage-9.2.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_android-7.0.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_android","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_android-1.0.52/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"open_file_android","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_android-1.0.6/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_android-2.2.18/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.20/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_app_check","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check-0.4.0+1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging-16.0.1/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_secure_storage_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_macos-3.1.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/venba/.pub-cache/hosted/pub.dev/google_sign_in_ios-6.1.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_darwin","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_darwin-1.6.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_mac","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_mac-1.0.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.2/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.5.4/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_macos","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-1.2.3/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_linux-0.0.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/","native_build":false,"dependencies":["path_provider_linux"],"dev_dependency":false},{"name":"url_launcher_linux","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"firebase_auth","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth-6.0.2/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core-4.1.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_secure_storage_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-3.1.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"local_auth_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/local_auth_windows-1.0.11/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"open_file_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/open_file_windows-0.0.3/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"package_info_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/package_info_plus-8.3.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/","native_build":false,"dependencies":["path_provider_windows"],"dev_dependency":false},{"name":"url_launcher_windows","path":"/home/venba/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/venba/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.5/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/venba/.pub-cache/hosted/pub.dev/file_picker-10.3.3/","dependencies":[],"dev_dependency":false},{"name":"firebase_app_check_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_app_check_web-0.2.0+16/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_auth_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_auth_web-6.0.2/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_core_web-3.1.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/home/venba/.pub-cache/hosted/pub.dev/firebase_messaging_web-4.0.1/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"flutter_secure_storage_web","path":"/home/venba/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-1.2.1/","dependencies":[],"dev_dependency":false},{"name":"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-10-16 15:48:13.675064","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 f3b5dae..8d8a1bc 100644 --- a/lib/core/routing/app_router.dart +++ b/lib/core/routing/app_router.dart @@ -11,6 +11,8 @@ import '../../presentation/providers/manager_provider.dart'; import '../../presentation/screens/Enquiry/enquiry/tabs.dart'; import '../../presentation/screens/Enquiry/policy_claims_endros/claims.dart'; import '../../presentation/screens/Enquiry/policy_claims_endros/endrosment.dart'; +import '../../presentation/screens/StaffAttendance/attendanceAllDetails.dart'; +import '../../presentation/screens/StaffAttendance/individual_Attendance.dart'; import '../../presentation/screens/UserManagement/Agent/agent.dart'; import '../../presentation/screens/UserManagement/Agent/agentList.dart'; import '../../presentation/screens/UserManagement/Profile/profile_mobile.dart'; @@ -160,6 +162,15 @@ final GoRouter appRouter = GoRouter( path: AppRoutes.enquiryHandlerLst, builder: (context, state) => const EnquiryHandler(), ), + GoRoute( + path: AppRoutes.allStaffAttendance, + builder: (context, state) => const AttendanceAllDetails(), + ), + + GoRoute( + path: AppRoutes.individualAttendance, + builder: (context, state) => const IndividualAttendanceDetails(), + ), ], redirect: (context, state) async { final loggedIn = await AuthService.isLoggedIn(); diff --git a/lib/core/routing/routes.dart b/lib/core/routing/routes.dart index 08c534f..816a171 100644 --- a/lib/core/routing/routes.dart +++ b/lib/core/routing/routes.dart @@ -13,6 +13,8 @@ class AppRoutes { static const String tabEnquiry = '/tabEnquiry'; static const String enquiryHandlerLst = '/enquiryHandlerLst'; + static const String allStaffAttendance = '/allStaffAttendance'; + static const String individualAttendance = '/individualAttendance'; static const String claimlist = '/claimList'; static const String endosement = '/endosement'; diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index cad0331..652da8a 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -586,6 +586,55 @@ class ApiService { return response; } + Future> fetchAttndanceOFAllStaffList({ + required String month, + }) async { + if (_token == null) { + await _initializeToken(); + } + + final String query; + + // if (role == 'manager') { + // query = 'manager_id=$id'; + // } + + final url = Uri.parse( + '${Env.apiUrl}staff/monthlyLoginCount?month=${month ?? ''}', + ); + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + + final response = await _makeGetRequest(url, headers); + return response; + } + + Future> fetchAttndanceOfIndiviualStaffList({ + String? month, + id, + }) async { + if (_token == null) { + await _initializeToken(); + } + + final String query; + + final url = Uri.parse( + '${Env.apiUrl}staff/staffLoggedDays?month=${month ?? ''}&staff_id=$id', + ); + + final headers = { + 'Authorization': 'Bearer $_token' ?? '', + 'App-Signature': 'nhance-partner-2025-signature-35468846JRhH551HK', + }; + + final response = await _makeGetRequest(url, headers); + return response; + } + Future> findSingleEnquiryData(id) async { // print(_token); if (_token == null) { diff --git a/lib/main.dart b/lib/main.dart index 1bbecd8..d6a7d55 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,14 +16,33 @@ Future _restoreManagerId(WidgetRef ref) async { final int? savedUserId = prefs.getInt('userId'); final String? savedUserRole = prefs.getString('userRole'); + final String? savedAttendanceIndvStaffId = prefs.getString( + 'attendanceIndvStaff', + ); + final String? savedAttendanceIndvStaffName = prefs.getString( + 'attendanceIndvStaffName', + ); + if (savedManagerId != null && savedUserId != null) { ref.read(managerIdProvider.notifier).state = savedManagerId; ref.read(userIdProvider.notifier).state = savedUserId; ref.read(userRoleProvider.notifier).state = savedUserRole; + print("Manager ID restored: $savedManagerId"); print("User ID restored: $savedUserId"); print("Role restored: $savedUserRole"); } + + if (savedAttendanceIndvStaffId != null && + savedAttendanceIndvStaffName != null) { + ref.read(staffIndiviualAttendanceIdProvider.notifier).state = + savedAttendanceIndvStaffId; + ref.read(staffIndiviualAttendanceNameIdProvider.notifier).state = + savedAttendanceIndvStaffName; + + print("Staff ID restored: $savedAttendanceIndvStaffId"); + print("Staff Name restored: $savedAttendanceIndvStaffName"); + } } Future main() async { diff --git a/lib/presentation/layouts/main_layout.dart b/lib/presentation/layouts/main_layout.dart index 0947f5a..78cd96a 100644 --- a/lib/presentation/layouts/main_layout.dart +++ b/lib/presentation/layouts/main_layout.dart @@ -97,12 +97,12 @@ class MainLayout extends StatelessWidget { body: Row( children: [ const SizedBox( - width: 90, // fixed width for drawer + width: 100, // fixed width for drawer child: DrawerMenu(), ), Expanded( child: Container( - padding: EdgeInsets.all(10.0), + padding: EdgeInsets.all(2.0), color: Colors.white, child: Column(children: [Expanded(child: body)]), ), diff --git a/lib/presentation/providers/manager_provider.dart b/lib/presentation/providers/manager_provider.dart index 0508ce3..099526f 100644 --- a/lib/presentation/providers/manager_provider.dart +++ b/lib/presentation/providers/manager_provider.dart @@ -5,3 +5,9 @@ final managerIdProvider = StateProvider((ref) => null); final userIdProvider = StateProvider((ref) => null); final enquiryIdProvider = StateProvider((ref) => null); final navFromEnqStaffProvider = StateProvider((ref) => null); +final staffIndiviualAttendanceIdProvider = StateProvider( + (ref) => null, +); +final staffIndiviualAttendanceNameIdProvider = StateProvider( + (ref) => null, +); diff --git a/lib/presentation/screens/StaffAttendance/attendanceAllDetails.dart b/lib/presentation/screens/StaffAttendance/attendanceAllDetails.dart new file mode 100644 index 0000000..15ab214 --- /dev/null +++ b/lib/presentation/screens/StaffAttendance/attendanceAllDetails.dart @@ -0,0 +1,662 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../../../../core/routing/routes.dart'; +import '../../../../core/services/api_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/date_field_theme.dart'; +import '../../themes/indicators/export_btn.dart'; +import '../../themes/indicators/month_field_theme.dart'; +import '../../themes/indicators/search_field_theme.dart'; +import '../../widgets/custom_Stdate_EnDate_Filter.dart'; +import '../../widgets/custom_action_popup.dart'; +import '../../widgets/custom_month_filter.dart'; + +class AttendanceAllDetails extends ConsumerStatefulWidget { + const AttendanceAllDetails({super.key}); + @override + ConsumerState createState() => + AttendanceAllDetailsState(); +} + +class AttendanceAllDetailsState extends ConsumerState { + int currentPage = 1; + int itemsPerPage = 10; + late ApiService apiService; + dynamic roleId; + dynamic userId; + final _formKey = GlobalKey(); + // final monthController = TextEditingController(); + final _monthFormKey = GlobalKey(); + + // List> dataVal = []; + List> getStaffData = []; + List> originalData = []; + List> filteredData = []; + + bool isLoading = false; + Map controllers = {}; + List tabHeader = ['startDate', 'endDate', 'month']; + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + + Future.microtask(() { + final id = ref.read(managerIdProvider); + roleId = ref.read(userRoleProvider); + userId = ref.read(userIdProvider); + + print("A56 => r : $roleId | mId: $id | uId: $userId "); + + // Staff - sanjeev.p@venbainfotech.com - T E S T S - 9 evarukku 8th id is manager + // Manager - venbalap08@gmail.com - T E S T M - 8 evarukku 8th id is manager + // Agent - venba2026@gmail.com - T E S T A - 5 evarkku 8th id is manager + // so here i used userId + + if (userId != null) { + getStaffList(userId, roleId); + } + }); + } + + void filterDateRange1() { + print("filterDateRange"); + // if (!_formKey.currentState!.validate()) return; + + // final fromDate = controllers['startDate']?.text ?? ''; + // final toDate = controllers['endDate']?.text ?? ''; + print("filterDateRange1"); + // Call with selected dates + getStaffList(userId, roleId); + } + + void filterMonth() { + print('Month'); + // ✅ Validate the form first + // if (!_formKey.currentState!.validate()) { + // // stop execution if validation fails + // return; + // } + + final fromDateText = controllers['month']?.text ?? ''; + print('monthmonth - $fromDateText'); + + if (fromDateText.isEmpty) { + print('No month selected'); + return; + } + + try { + // Convert "10-2025" → "2025-10" + final parsedDate = DateFormat('MM-yyyy').parse(fromDateText); + final apiMonth = DateFormat('yyyy-MM').format(parsedDate); + + print('Converted month for API: $apiMonth'); + + // ✅ Call your API with the converted format + getStaffList(userId, roleId, month: apiMonth); + } catch (e) { + print('Error parsing month: $e'); + } + } + + void refrshfilterDateRange() { + setState(() { + controllers['month']!.clear(); + controllers['month']?.text = ''; + // Reset the FormField validation + _formKey.currentState?.reset(); + _monthFormKey.currentState?.reset(); + }); + getStaffList(userId, roleId); + } + + Future getStaffList(int managerId, role, {String month = ''}) async { + final monthForApi = month.isNotEmpty + ? month + : DateFormat('yyyy-MM').format(DateTime.now()); + + print('A72 => Fns called => $managerId | $role | month: $monthForApi'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchAttndanceOFAllStaffList( + month: monthForApi, + // toDate: controllers['endDate']?.text ?? '', + ); + + if (response['status'] == 'success') { + final data = response['data']; + final fromDate = response['month'] ?? ''; + + print('FromDate : $fromDate'); + print('Frdata : $data'); + + setState(() { + print('test 1'); + + if (fromDate != null && fromDate.isNotEmpty) { + // Parse the string to DateTime first + final parsedDate = DateFormat('yyyy-MM').parse(fromDate); + final monthText = DateFormat('MM-yyyy').format(parsedDate); + controllers['month']?.text = monthText; + } + // controllers['endDate']?.text = toDate; + // if (data is List) { + // getStaffData = List>.from(data); + // } else if (data is Map) { + // getStaffData = [Map.from(data)]; + // } else { + // getStaffData = []; + // } + // if (data is List) { + // // Safely map each item to Map + // // getStaffData = data.map>((item) { + // // if (item is Map) return item; + // // if (item is Map) return Map.from(item); + // // return {}; // fallback empty map + // // }).toList(); + // // Convert JSArray safely to List> + // + // } else if (data is Map) { + // getStaffData = [Map.from(data)]; + // } else { + // getStaffData = []; + // } + print('test 2'); + getStaffData = (data as List) + .map>( + (item) => Map.from(item), + ) + .toList(); + print('test 3'); + originalData = getStaffData; + filteredData = List.from(originalData); + print('testfilteredData $filteredData'); + }); + } else { + getStaffData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + List get _paginatedData { + print('test 31'); + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['staff_id']) - int.parse(a['staff_id'])); + + print('test 311- $sortedData'); + print('test 311'); + if (sortedData.isEmpty) return []; + + // Ensure currentPage is valid + final maxPage = (sortedData.length / itemsPerPage).ceil(); + final safePage = currentPage.clamp(1, maxPage); + + final startIndex = (safePage - 1) * itemsPerPage; + final endIndex = (startIndex + itemsPerPage).clamp(0, sortedData.length); + + return sortedData.sublist(startIndex, endIndex); + } + + Future handleEdit(item) async { + // Navigator.pop(context); + print('EDITStaff - ${item['staff_id']}'); + // dynamic id = data['id']; + // context.go('/tabEnquiry/$id'); + + final prefs = await SharedPreferences.getInstance(); + + // ✅ Remove old value (if any) + await prefs.remove('attendanceIndvStaff'); + await prefs.remove('attendanceIndvStaffName'); + + // setState(() { + final id = item['staff_id'].toString(); + final name = item['staff_name'].toString(); + // ✅ Save the new id + await prefs.setString('attendanceIndvStaff', id.toString()); + await prefs.setString('attendanceIndvStaffName', name.toString()); + ref.read(staffIndiviualAttendanceIdProvider.notifier).state = id; + ref.read(staffIndiviualAttendanceNameIdProvider.notifier).state = name; + + // }); + // update provider + + // context.go(AppRoutes.tabEnquiry); + context.go(AppRoutes.individualAttendance); + } + + void filterData(String query) { + print("FilterDAta - $query"); + setState(() { + print('test 31f'); + filteredData = getStaffData.where((item) { + // final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive"; + + return (item['staff_name'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['month'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['login_count'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ); + }).toList(); + }); + } + + final TextEditingController _searchStaffController = TextEditingController(); + + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat('dd-MM-yyyy HH:mm').format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } + + @override + Widget build(BuildContext context) { + return MainLayout( + title: "Staff Attendance", + body: Container( + // color: Colors.yellow.shade50, + width: MediaQuery.of(context).size.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + height: 30, + width: MediaQuery.of(context).size.width, + child: GestureDetector( + onTap: () { + context.go(AppRoutes.dashboard); + }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Tooltip( + message: 'Back', + child: IconButton( + icon: Icon( + Icons.arrow_left_sharp, + size: ResponsiveLayout.isMobile(context) ? 25 : 25, + color: const Color(0xFF425B5B), + ), + onPressed: () { + context.go(AppRoutes.dashboard); + }, + splashRadius: 18, + hoverColor: Colors.black12, + padding: const EdgeInsets.all(4), + constraints: const BoxConstraints(), + ), + ), + const SizedBox(width: 5), // spacing between icon and text + Text( + "Staff Attendance", + style: GoogleFonts.inter( + fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + + SizedBox(height: ResponsiveLayout.isMobile(context) ? 5 : 5), + Expanded( + child: Container( + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.all(8.0), + child: _buildContent(context), + ), + ), + + Container( + // height: 20, + width: MediaQuery.of(context).size.width, + // color: Colors.green.shade50, + child: PaginationControls( + currentPage: currentPage, + itemsPerPage: itemsPerPage, + // totalItems: dataVal.length, + totalItems: filteredData.length, + // activeColor: layoutColor, // your theme color + onPageChanged: (page) { + setState(() { + currentPage = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage = items; + currentPage = 1; + }); + }, + ), + ), + ], + ), + ), + ); + } + + Widget _buildContent(BuildContext context) { + return Column( + children: [ + Container( + // height: 40, + // color: Colors.pink, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MonthFilterRow( + monthController: controllers['month']!, + formKey: _monthFormKey, + onFilter: () { + print( + 'Filter triggered with month: ${controllers['month']!.text}', + ); + filterMonth(); + }, + onRefresh: () { + controllers['month']!.clear(); + refrshfilterDateRange(); + print('Month filter cleared'); + }, + ), + + Spacer(), + + ThemedSearchField( + hintText: 'Search', + backgroundColor: Color(0xFFF6F8F8), + onChanged: filterData, + controller: _searchStaffController, + txtwidth: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.width * 0.6 + : MediaQuery.of(context).size.width * 0.2, + ), + ResponsiveLayout.isMobile(context) + ? Spacer() + : SizedBox(width: 10), + + ExportBtn( + sheetName: "Staff Attendance", + fileName: "staff_attendance_list", + data: filteredData, + txt: !ResponsiveLayout.isMobile(context) ? true : false, + headers: ["staff_id", "staff_name", "month", "login_count"], + ), + ], + ), + ), + SizedBox(height: 10), + + Container( + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Row( + children: [ + Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)), + Expanded(flex: 2, child: Text('Staff Name', style: _headerStyle)), + + Expanded(flex: 2, child: Text('Month', style: _headerStyle)), + Expanded( + flex: 2, + child: Text('Login Count', style: _headerStyle), + ), + Expanded(flex: 2, child: Text('Action', style: _headerStyle)), + ], + ), + ), + + ResponsiveLayout.isMobile(context) + ? _buildDataTable(context) + : Expanded(child: _buildDataTable(context)), + ], + ); + } + + Widget _buildDataTable(BuildContext context) { + print('test 32'); + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + final sortedData = [..._paginatedData]; + print('test 4'); + + // Desktop: keep ListView.builder + return ListView.builder( + itemCount: sortedData.length + 1, + itemBuilder: (context, index) { + if (index == 0) return _buildHeader(); + final startIndex = (currentPage - 1) * itemsPerPage; + final item = sortedData[index - 1]; + final sno = startIndex + index; + return _buildDataRow(item, sno); + }, + ); + } + + Widget _buildHeader() { + return SizedBox.shrink(); + } + + Widget _buildDataRow(Map item, sno) { + print('test 5'); + return Container( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 16), + // margin: const EdgeInsets.only(top: 10), + decoration: BoxDecoration( + color: Colors.white, + // color: Color(0xFFE0F7F9), + border: const Border( + bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)), + Expanded( + flex: 2, + child: Text( + item['staff_name']?.toString() ?? '-', + style: _dataBold, + ), + ), + + Expanded( + flex: 2, + child: Text(item['month']?.toString() ?? '-', style: _dataBold), + ), + + Expanded( + flex: 2, + child: Text( + item['login_count']?.toString() ?? '-', + style: _dataBold, + ), + ), + + Expanded( + flex: 2, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Tooltip( + message: 'Edit', + child: IconButton( + icon: Image.asset( + "assets/miscellaneous/Edit.png", + height: 15, + width: 15, + ), + onPressed: () { + handleEdit(item); + }, + splashRadius: 28, + hoverColor: Colors.black12, + padding: const EdgeInsets.all(8), + constraints: const BoxConstraints(), + ), + ), + ], + ), + ), + ), + ], + ), + ); + } + + Widget buildStartDate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Start Date', style: _textStyle), + SizedBox(height: 5), + + ThemedMonthField( + hintText: "Select Month", + txtwidth: MediaQuery.of(context).size.width * 0.27, + txtheight: 40, + backgroundColor: const Color(0xFFECECEC), + validator: (value) => Validators.requiredField(value, "date"), + borderColor: Colors.grey.shade300, + controller: controllers['startDate']!, + onDateSelected: (date) { + print("Picked Date: $date"); + + controllers['startDate']?.text = DateFormat('MM-yyyy').format(date); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + Widget buildEndDate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('End Date', style: _textStyle), + SizedBox(height: 5), + ThemedDateField( + hintText: "Select Date", + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.16, + // txtheight: 50, + // backgroundColor: const Color(0xFFECECEC), + validator: (value) { + if (value == null || value.isEmpty) { + return "End Date is required"; + } + + final fromText = controllers['startDate']?.text ?? ''; + if (fromText.isNotEmpty) { + final startDate = DateFormat('dd-MM-yyyy').parse(fromText); + final endDate = DateFormat('dd-MM-yyyy').parse(value); + + if (endDate.isBefore(startDate)) { + return "End Date cannot be earlier than Start Date"; + } + } + return null; // ✅ no error + }, + controller: controllers['endDate']!, + lastDate: DateTime.now(), + onDateSelected: (date) { + print("Picked Date: $date"); + controllers['endDate']?.text = DateFormat( + 'dd-MM-yyyy', + ).format(date); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + static final _dataBold = GoogleFonts.inter( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = GoogleFonts.inter( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + // static const _headerStyle = GoogleFonts.inter( + // color: Colors.black, + // fontWeight: FontWeight.bold, + // ); + static final _headerStyle = GoogleFonts.inter( + color: Colors.black, + fontWeight: FontWeight.bold, + ); + static final _cardheaderStyle = GoogleFonts.inter( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static final _cardBodyStyle = GoogleFonts.inter( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); + + static const _textStyle = TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ); +} diff --git a/lib/presentation/screens/StaffAttendance/individual_Attendance.dart b/lib/presentation/screens/StaffAttendance/individual_Attendance.dart new file mode 100644 index 0000000..c1797c6 --- /dev/null +++ b/lib/presentation/screens/StaffAttendance/individual_Attendance.dart @@ -0,0 +1,602 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart'; +import 'package:intl/intl.dart'; +import 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../../../../core/routing/routes.dart'; +import '../../../../core/services/api_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/date_field_theme.dart'; +import '../../themes/indicators/export_btn.dart'; +import '../../themes/indicators/month_field_theme.dart'; +import '../../themes/indicators/search_field_theme.dart'; +import '../../widgets/custom_Stdate_EnDate_Filter.dart'; +import '../../widgets/custom_action_popup.dart'; +import '../../widgets/custom_month_filter.dart'; + +class IndividualAttendanceDetails extends ConsumerStatefulWidget { + const IndividualAttendanceDetails({super.key}); + @override + ConsumerState createState() => + IndividualAttendanceDetailsState(); +} + +class IndividualAttendanceDetailsState + extends ConsumerState { + int currentPage = 1; + int itemsPerPage = 10; + late ApiService apiService; + dynamic staffId; + dynamic staffName; + dynamic userId; + final _formKey = GlobalKey(); + // final monthController = TextEditingController(); + final _monthFormKey = GlobalKey(); + + // List> dataVal = []; + List> getStaffData = []; + List> originalData = []; + List> filteredData = []; + + bool isLoading = false; + Map controllers = {}; + List tabHeader = ['startDate', 'endDate', 'month']; + + @override + void initState() { + super.initState(); + + apiService = ApiService(); + for (String field in tabHeader) { + controllers[field] = TextEditingController(); + } + + Future.microtask(() { + final id = ref.read(managerIdProvider); + staffId = ref.read(staffIndiviualAttendanceIdProvider); + staffName = ref.read(staffIndiviualAttendanceNameIdProvider); + userId = ref.read(userIdProvider); + + print( + "A56 => r : $staffId | mId: $id | uId: $userId |staffName : $staffName", + ); + + // Staff - sanjeev.p@venbainfotech.com - T E S T S - 9 evarukku 8th id is manager + // Manager - venbalap08@gmail.com - T E S T M - 8 evarukku 8th id is manager + // Agent - venba2026@gmail.com - T E S T A - 5 evarkku 8th id is manager + // so here i used userId + + if (staffId != null && staffName != null) { + getStaffList(userId, staffId); + } + }); + } + + void filterDateRange1() { + print("filterDateRange"); + // if (!_formKey.currentState!.validate()) return; + + // final fromDate = controllers['startDate']?.text ?? ''; + // final toDate = controllers['endDate']?.text ?? ''; + print("filterDateRange1"); + // Call with selected dates + getStaffList(userId, staffId); + } + + void filterMonth() { + print('Month'); + // ✅ Validate the form first + // if (!_formKey.currentState!.validate()) { + // // stop execution if validation fails + // return; + // } + + final fromDateText = controllers['month']?.text ?? ''; + print('monthmonth - $fromDateText'); + + if (fromDateText.isEmpty) { + print('No month selected'); + return; + } + + try { + // Convert "10-2025" → "2025-10" + final parsedDate = DateFormat('MM-yyyy').parse(fromDateText); + final apiMonth = DateFormat('yyyy-MM').format(parsedDate); + + print('Converted month for API: $apiMonth'); + + // ✅ Call your API with the converted format + getStaffList(userId, staffId, month: apiMonth); + } catch (e) { + print('Error parsing month: $e'); + } + } + + void refrshfilterDateRange() { + setState(() { + controllers['month']!.clear(); + controllers['month']?.text = ''; + + // Reset the FormField validation + _formKey.currentState?.reset(); + _monthFormKey.currentState?.reset(); + }); + getStaffList(userId, staffId); + } + + Future getStaffList(int managerId, role, {String month = ''}) async { + final monthForApi = month.isNotEmpty + ? month + : DateFormat('yyyy-MM').format(DateTime.now()); + + print('A72 => Fns called => $managerId | $role | month: $monthForApi'); + setState(() { + isLoading = true; + }); + + try { + final response = await apiService.fetchAttndanceOfIndiviualStaffList( + month: monthForApi, + id: staffId, + // toDate: controllers['endDate']?.text ?? '', + ); + + if (response['status'] == 'success') { + final data = response['data']; + final fromDate = response['month'] ?? ''; + + print('FromDate : $fromDate'); + print('Frdata : $data'); + + setState(() { + print('test 1'); + + if (fromDate != null && fromDate.isNotEmpty) { + // Parse the string to DateTime first + final parsedDate = DateFormat('yyyy-MM').parse(fromDate); + final monthText = DateFormat('MM-yyyy').format(parsedDate); + controllers['month']?.text = monthText; + } + + print('test 2'); + getStaffData = (data as List) + .map>( + (item) => Map.from(item), + ) + .toList(); + print('test 3'); + originalData = getStaffData; + filteredData = List.from(originalData); + print('testfilteredData $filteredData'); + }); + } else { + getStaffData = []; + originalData = []; + } + } catch (e) { + print('Exception occurred: $e'); + } finally { + setState(() { + isLoading = false; + }); + } + } + + List get _paginatedData { + print('test 31'); + // Sort descending by id first + final sortedData = [...filteredData] + ..sort((a, b) => int.parse(b['id']) - int.parse(a['id'])); + + print('test 311- $sortedData'); + print('test 311'); + if (sortedData.isEmpty) return []; + + // Ensure currentPage is valid + final maxPage = (sortedData.length / itemsPerPage).ceil(); + final safePage = currentPage.clamp(1, maxPage); + + final startIndex = (safePage - 1) * itemsPerPage; + final endIndex = (startIndex + itemsPerPage).clamp(0, sortedData.length); + + return sortedData.sublist(startIndex, endIndex); + } + + Future handleEdit(item) async { + // Navigator.pop(context); + print('EDITStaff - ${item['id']}'); + // dynamic id = data['id']; + // context.go('/tabEnquiry/$id'); + + final prefs = await SharedPreferences.getInstance(); + + // ✅ Remove old value (if any) + await prefs.remove('enqAgentDataId'); + + // setState(() { + final id = item['id'].toString(); + // ✅ Save the new id + await prefs.setString('enqAgentDataId', id.toString()); + ref.read(enquiryIdProvider.notifier).state = id; + + // }); + // update provider + + context.go(AppRoutes.tabEnquiry); + } + + void filterData(String query) { + print("FilterDAta - $query"); + setState(() { + print('test 31f'); + filteredData = getStaffData.where((item) { + // final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive"; + + return (item['login_date'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ) || + (item['logout_date'] ?? '-').toLowerCase().contains( + query.toLowerCase(), + ); + }).toList(); + }); + } + + final TextEditingController _searchStaffController = TextEditingController(); + + String _formatDate(String rawDate) { + try { + final dateTime = DateTime.parse(rawDate); + return DateFormat('dd-MM-yyyy HH:mm').format(dateTime); // 24-hour format + } catch (e) { + return rawDate; // fallback if parsing fails + } + } + + @override + Widget build(BuildContext context) { + return MainLayout( + title: "Staff Attendance", + body: Container( + // color: Colors.yellow.shade50, + width: MediaQuery.of(context).size.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + height: 30, + width: MediaQuery.of(context).size.width, + child: GestureDetector( + onTap: () { + context.go(AppRoutes.allStaffAttendance); + }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Tooltip( + message: 'Back', + child: IconButton( + icon: Icon( + Icons.arrow_left_sharp, + size: ResponsiveLayout.isMobile(context) ? 25 : 25, + color: const Color(0xFF425B5B), + ), + onPressed: () async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('attendanceIndvStaff'); + await prefs.remove('attendanceIndvStaffName'); + context.go(AppRoutes.allStaffAttendance); + }, + splashRadius: 18, + hoverColor: Colors.black12, + padding: const EdgeInsets.all(4), + constraints: const BoxConstraints(), + ), + ), + const SizedBox(width: 5), // spacing between icon and text + Text( + "Attendance For $staffName", + style: GoogleFonts.inter( + fontSize: ResponsiveLayout.isMobile(context) ? 14 : 18, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ), + + SizedBox(height: ResponsiveLayout.isMobile(context) ? 5 : 5), + Expanded( + child: Container( + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.all(8.0), + child: _buildContent(context), + ), + ), + + Container( + // height: 20, + width: MediaQuery.of(context).size.width, + // color: Colors.green.shade50, + child: PaginationControls( + currentPage: currentPage, + itemsPerPage: itemsPerPage, + // totalItems: dataVal.length, + totalItems: filteredData.length, + // activeColor: layoutColor, // your theme color + onPageChanged: (page) { + setState(() { + currentPage = page; + }); + }, + onItemsPerPageChanged: (items) { + setState(() { + itemsPerPage = items; + currentPage = 1; + }); + }, + ), + ), + ], + ), + ), + ); + } + + Widget _buildContent(BuildContext context) { + return Column( + children: [ + Container( + // height: 40, + // color: Colors.pink, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MonthFilterRow( + monthController: controllers['month']!, + formKey: _monthFormKey, + onFilter: () { + print( + 'Filter triggered with month: ${controllers['month']!.text}', + ); + filterMonth(); + }, + onRefresh: () { + controllers['month']!.clear(); + refrshfilterDateRange(); + print('Month filter cleared'); + }, + ), + + Spacer(), + + ThemedSearchField( + hintText: 'Search', + backgroundColor: Color(0xFFF6F8F8), + onChanged: filterData, + controller: _searchStaffController, + txtwidth: ResponsiveLayout.isMobile(context) + ? MediaQuery.of(context).size.width * 0.6 + : MediaQuery.of(context).size.width * 0.2, + ), + ResponsiveLayout.isMobile(context) + ? Spacer() + : SizedBox(width: 10), + + ExportBtn( + sheetName: "Staff Individual Attendance", + fileName: "staff_individual_attendance_list", + data: filteredData, + txt: !ResponsiveLayout.isMobile(context) ? true : false, + headers: ["id", "login_date", "logout_date"], + ), + ], + ), + ), + SizedBox(height: 10), + + Container( + decoration: BoxDecoration( + color: Color(0xFFEDF6F5), + borderRadius: BorderRadius.circular(6), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + child: Row( + children: [ + Expanded(flex: 1, child: Text('S.No.', style: _headerStyle)), + Expanded(flex: 2, child: Text('Login Date', style: _headerStyle)), + + Expanded( + flex: 2, + child: Text('Logout Date', style: _headerStyle), + ), + ], + ), + ), + + ResponsiveLayout.isMobile(context) + ? _buildDataTable(context) + : Expanded(child: _buildDataTable(context)), + ], + ); + } + + Widget _buildDataTable(BuildContext context) { + print('test 32'); + if (filteredData.isEmpty) { + return const SizedBox( + height: 50, + child: Center(child: Text('No available data')), + ); + } + + final sortedData = [..._paginatedData]; + print('test 4'); + + // Desktop: keep ListView.builder + return ListView.builder( + itemCount: sortedData.length + 1, + itemBuilder: (context, index) { + if (index == 0) return _buildHeader(); + final startIndex = (currentPage - 1) * itemsPerPage; + final item = sortedData[index - 1]; + final sno = startIndex + index; + return _buildDataRow(item, sno); + }, + ); + } + + Widget _buildHeader() { + return SizedBox.shrink(); + } + + Widget _buildDataRow(Map item, sno) { + print('test 5'); + return Container( + padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 16), + // margin: const EdgeInsets.only(top: 10), + decoration: BoxDecoration( + color: Colors.white, + // color: Color(0xFFE0F7F9), + border: const Border( + bottom: BorderSide(color: Color(0xFFEAEAEA), width: 1), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Expanded(flex: 1, child: Text('$sno' ?? '-', style: _dataBold)), + Expanded( + flex: 2, + child: Text(item['login_date'] ?? '-', style: _dataBold), + ), + + Expanded( + flex: 2, + child: Text(item['logout_date'] ?? '-', style: _dataBold), + ), + ], + ), + ); + } + + Widget buildStartDate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Start Date', style: _textStyle), + SizedBox(height: 5), + + ThemedMonthField( + hintText: "Select Month", + txtwidth: MediaQuery.of(context).size.width * 0.27, + txtheight: 40, + backgroundColor: const Color(0xFFECECEC), + validator: (value) => Validators.requiredField(value, "date"), + borderColor: Colors.grey.shade300, + controller: controllers['startDate']!, + onDateSelected: (date) { + print("Picked Date: $date"); + + controllers['startDate']?.text = DateFormat('MM-yyyy').format(date); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + Widget buildEndDate(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('End Date', style: _textStyle), + SizedBox(height: 5), + ThemedDateField( + hintText: "Select Date", + txtwidth: ResponsiveLayout.isMobile(context) + ? null + : MediaQuery.of(context).size.width * 0.16, + // txtheight: 50, + // backgroundColor: const Color(0xFFECECEC), + validator: (value) { + if (value == null || value.isEmpty) { + return "End Date is required"; + } + + final fromText = controllers['startDate']?.text ?? ''; + if (fromText.isNotEmpty) { + final startDate = DateFormat('dd-MM-yyyy').parse(fromText); + final endDate = DateFormat('dd-MM-yyyy').parse(value); + + if (endDate.isBefore(startDate)) { + return "End Date cannot be earlier than Start Date"; + } + } + return null; // ✅ no error + }, + controller: controllers['endDate']!, + lastDate: DateTime.now(), + onDateSelected: (date) { + print("Picked Date: $date"); + controllers['endDate']?.text = DateFormat( + 'dd-MM-yyyy', + ).format(date); + // controllers['date']?.text = date as String; + }, + ), + ], + ); + } + + static final _dataBold = GoogleFonts.inter( + fontSize: 14, + + fontWeight: FontWeight.w400, + color: Color(0xFF000000), + ); + + static final _dataSub = GoogleFonts.inter( + fontSize: 10, + fontWeight: FontWeight.w300, + color: Color(0xFF585757), + ); + + // static const _headerStyle = GoogleFonts.inter( + // color: Colors.black, + // fontWeight: FontWeight.bold, + // ); + static final _headerStyle = GoogleFonts.inter( + color: Colors.black, + fontWeight: FontWeight.bold, + ); + static final _cardheaderStyle = GoogleFonts.inter( + color: Colors.black, + fontWeight: FontWeight.w600, + fontSize: 12, + ); + + static final _cardBodyStyle = GoogleFonts.inter( + color: Color(0xFF545454), + fontWeight: FontWeight.w400, + fontSize: 12, + ); + + static const _textStyle = TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ); +} diff --git a/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart b/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart index 209f807..5078308 100644 --- a/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart +++ b/lib/presentation/screens/UserManagement/Profile/profile_mobile.dart @@ -2,6 +2,7 @@ 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 'package:nhance_partner/presentation/providers/userRoleProvider.dart'; import '../../../../core/services/api_service.dart'; import '../../../../data/services/auth_service.dart'; @@ -25,6 +26,7 @@ class ProfileState extends ConsumerState { dynamic roleIdRaw; dynamic roleId; + dynamic role; bool isProfile = true; bool isLoading = false; @@ -36,14 +38,6 @@ class ProfileState extends ConsumerState { 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 { @@ -55,8 +49,12 @@ class ProfileState extends ConsumerState { }); print('profileDatadecodedTokenProfile : $decodedToken'); print('profileDatadecodedTokenProfile : $profileData'); - - await getList(); + Future.microtask(() { + role = ref.read(userRoleProvider); + if (role != null) { + getList(); + } + }); } Future getList() async { @@ -71,7 +69,7 @@ class ProfileState extends ConsumerState { if (managerId != null) { getIncenctiveFileList(managerId); } - } else if (roleId != 1 && roleId != 2) { + } else if (roleId != 1 && roleId != 2 && roleId != 3) { final agentIdRaw = profileData?['id']; final agentId = agentIdRaw is String ? int.tryParse(agentIdRaw) @@ -185,9 +183,7 @@ class ProfileState extends ConsumerState { ? EdgeInsets.all(8.0) : null, child: isLoading - ? const Center( - child: Text("No incentive files found"), - ) + ? const Center(child: CircularProgressIndicator()) : Column( children: [ // const SizedBox(height: 25), @@ -212,7 +208,8 @@ class ProfileState extends ConsumerState { style: _headerStyle, ), Text( - profileData?['emp_id'] ?? '-', + // profileData?['role'] ?? '-', + role ?? '-', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, diff --git a/lib/presentation/screens/UserManagement/Profile/profile_web.dart b/lib/presentation/screens/UserManagement/Profile/profile_web.dart index c86d4be..dc7682d 100644 --- a/lib/presentation/screens/UserManagement/Profile/profile_web.dart +++ b/lib/presentation/screens/UserManagement/Profile/profile_web.dart @@ -8,6 +8,7 @@ import '../../../../data/services/auth_service.dart'; import '../../../layouts/main_layout.dart'; import '../../../layouts/responsive_layout.dart'; import '../../../providers/manager_provider.dart'; +import '../../../providers/userRoleProvider.dart'; class ProfilePopUp extends ConsumerStatefulWidget { const ProfilePopUp({super.key}); @@ -25,6 +26,7 @@ class ProfilePopUpState extends ConsumerState { dynamic roleIdRaw; dynamic roleId; + dynamic role; bool isProfile = true; bool isLoading = false; @@ -56,10 +58,21 @@ class ProfilePopUpState extends ConsumerState { print('profileDatadecodedTokenProfile : $decodedToken'); print('profileDatadecodedTokenProfile : $profileData'); - await getList(); + // await getList(); + + Future.microtask(() { + role = ref.read(userRoleProvider); + if (role != null) { + getList(); + } + }); } Future getList() async { + setState(() { + isLoading = true; + }); + roleIdRaw = profileData?['role_id']; roleId = roleIdRaw is String ? int.tryParse(roleIdRaw) : roleIdRaw as int?; @@ -80,6 +93,10 @@ class ProfilePopUpState extends ConsumerState { getIncenctiveFileList(agentId); } } + + setState(() { + isLoading = false; + }); } Future getIncenctiveFileList(id) async { @@ -187,7 +204,7 @@ class ProfilePopUpState extends ConsumerState { ? EdgeInsets.all(16.0) : null, child: isLoading - ? const Center(child: Text("No incentive files found")) + ? const Center(child: CircularProgressIndicator()) : Column( children: [ const SizedBox(height: 25), @@ -210,7 +227,7 @@ class ProfilePopUpState extends ConsumerState { style: _headerStyle, ), Text( - profileData?['emp_id'] ?? '-', + role ?? '-', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, diff --git a/lib/presentation/widgets/custom_month_filter.dart b/lib/presentation/widgets/custom_month_filter.dart new file mode 100644 index 0000000..27564b2 --- /dev/null +++ b/lib/presentation/widgets/custom_month_filter.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +import '../themes/indicators/month_field_theme.dart'; + +class MonthFilterRow extends StatelessWidget { + final TextEditingController monthController; + final VoidCallback onFilter; + final VoidCallback onRefresh; + final GlobalKey formKey; + final bool isMobile; + + const MonthFilterRow({ + super.key, + required this.monthController, + required this.onFilter, + required this.onRefresh, + required this.formKey, + this.isMobile = false, + }); + + @override + Widget build(BuildContext context) { + final spacing = 10.0; + + final fieldAndButtons = [ + buildMonthField(context), + SizedBox(width: spacing), + Tooltip( + message: 'Filter', + child: IconButton( + icon: const Icon(Icons.filter_alt_outlined), + onPressed: () { + if (formKey.currentState!.validate()) onFilter(); + }, + ), + ), + Tooltip( + message: 'Refresh', + child: IconButton( + icon: const Icon(Icons.refresh), + onPressed: onRefresh, + ), + ), + ]; + + return Form( + key: formKey, + child: isMobile + ? Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + buildMonthField(context), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Tooltip( + message: 'Filter', + child: IconButton( + icon: const Icon(Icons.filter_alt_outlined), + onPressed: () { + if (formKey.currentState!.validate()) onFilter(); + }, + ), + ), + Tooltip( + message: 'Refresh', + child: IconButton( + icon: const Icon(Icons.refresh), + onPressed: onRefresh, + ), + ), + ], + ), + ], + ) + : Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: fieldAndButtons, + ), + ); + } + + Widget buildMonthField(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Month', style: _textStyle), + const SizedBox(height: 5), + ThemedMonthField( + hintText: "Select Month", + txtwidth: MediaQuery.of(context).size.width * 0.2, + txtheight: 40, + // backgroundColor: const Color(0xFFECECEC), + backgroundColor: const Color(0xFFFFFFFF), + validator: (value) => + value == null || value.isEmpty ? "Month is required" : null, + borderColor: Colors.grey.shade100, + controller: monthController, + onDateSelected: (date) { + monthController.text = DateFormat('MM-yyyy').format(date); + }, + ), + ], + ); + } + + static const _textStyle = TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + ); +} diff --git a/lib/presentation/widgets/drawer_menu.dart b/lib/presentation/widgets/drawer_menu.dart index 1e627f3..f1fd697 100644 --- a/lib/presentation/widgets/drawer_menu.dart +++ b/lib/presentation/widgets/drawer_menu.dart @@ -156,6 +156,16 @@ class DrawerMenuState extends ConsumerState { label: "Reports", popupKey: 'Reports', ), + + if (roleId == 'manager') + _buildMenuItem( + context: context, + icon: Icon(Icons.access_time, size: 30, color: Colors.black), + label: "Staff Attendance", + onTap: () { + context.go(AppRoutes.allStaffAttendance); + }, + ), ], ), ); @@ -215,17 +225,41 @@ class DrawerLabel extends StatelessWidget { @override Widget build(BuildContext context) { - return Row( + // Split the text by space (e.g. "Staff Attendance" → ["Staff", "Attendance"]) + final parts = text.split(' '); + + return Column( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - text, + children: parts.map((line) { + return Text( + line, style: GoogleFonts.inter(color: Colors.white, fontSize: 11.5), - ), - const SizedBox(height: 20), - ], + textAlign: TextAlign.center, + ); + }).toList(), ); } + + // Widget build(BuildContext context) { + // return Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // SizedBox( + // width: 70, + // child: Align( + // alignment: Alignment.center, + // child: Text( + // text, + // style: GoogleFonts.inter(color: Colors.white, fontSize: 11.5), + // softWrap: true, + // maxLines: 2, + // ), + // ), + // ), + // const SizedBox(height: 20), + // ], + // ); + // } } // Popup item diff --git a/lib/presentation/widgets/mobile_tabs.dart b/lib/presentation/widgets/mobile_tabs.dart index 1880d04..d9ad406 100644 --- a/lib/presentation/widgets/mobile_tabs.dart +++ b/lib/presentation/widgets/mobile_tabs.dart @@ -85,16 +85,18 @@ class _MobileBottomMenuState extends ConsumerState { } break; + // case 3: + // // User options only for manager + // if (roleId == 'manager') { + // _showOptionsSheet([ + // {'label': 'Agent', 'route': AppRoutes.agentLst}, + // {'label': 'Staff', 'route': AppRoutes.staffLst}, + // ]); + // } + // break; + case 3: - // User options only for manager - if (roleId == 'manager') { - _showOptionsSheet([ - {'label': 'Agent', 'route': AppRoutes.agentLst}, - {'label': 'Staff', 'route': AppRoutes.staffLst}, - ]); - } else { - context.go(AppRoutes.profile); - } + context.go(AppRoutes.profile); break; } }, @@ -135,14 +137,23 @@ class _MobileBottomMenuState extends ConsumerState { ), label: "Enquiry", ), - + // if (roleId == 'manager') ...[ + // BottomNavigationBarItem( + // icon: Icon( + // Icons.person_add_alt, + // size: 24, + // color: _currentIndex == 3 ? Colors.white : Colors.black, + // ), + // label: "User", + // ), + // ], BottomNavigationBarItem( icon: Icon( - Icons.person_add_alt, + Icons.person_outline, size: 24, color: _currentIndex == 3 ? Colors.white : Colors.black, ), - label: "User", + label: "Profile", ), ], );