From 1e50a7ec878ef1eebc97a7c0133b4931e160042b Mon Sep 17 00:00:00 2001 From: Ashwin Date: Wed, 30 Jul 2025 19:11:26 +0530 Subject: [PATCH 1/9] feat: Enhance BottleCRM Mobile with Google Sign-In integration and modular architecture - Updated README.md to reflect the new mobile app features, requirements, and setup instructions. - Modified android/app/google-services.json for updated project configuration. - Implemented Google Sign-In in auth_bloc.dart, replacing traditional login method. - Updated crm_services.dart to handle Google login requests with JWT token exchange. - Refactored login.dart to streamline the login process and improve UI/UX. - Added api_config.dart for environment-based API URL management. - Updated pubspec.yaml to include google_sign_in package dependency. - Revised widget tests to validate Google login functionality. - Created CLAUDE.md for project guidelines and architecture overview. --- .flutter-plugins-dependencies | 2 +- CLAUDE.md | 138 ++++ README.md | 120 ++- android/app/google-services.json | 22 +- lib/bloc/auth_bloc.dart | 35 +- lib/config/api_config.dart | 41 + lib/services/crm_services.dart | 15 +- lib/ui/screens/authentication/login.dart | 909 ++++++++++------------- pubspec.yaml | 1 + test/widget_test.dart | 10 +- 10 files changed, 737 insertions(+), 556 deletions(-) create mode 100644 CLAUDE.md create mode 100644 lib/config/api_config.dart diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 130f7a6..0ff1290 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/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_ios-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_android-0.0.1+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_macos-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_linux-0.0.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_windows-0.0.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_analytics_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics_web-0.6.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core_web-3.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_web-0.0.2/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/ashwin/.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":"file_selector_linux","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_temp_fork","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"quill_native_bridge","dependencies":["quill_native_bridge_android","quill_native_bridge_web","quill_native_bridge_windows","quill_native_bridge_linux","quill_native_bridge_ios","quill_native_bridge_macos"]},{"name":"quill_native_bridge_android","dependencies":[]},{"name":"quill_native_bridge_ios","dependencies":[]},{"name":"quill_native_bridge_linux","dependencies":["file_selector_linux"]},{"name":"quill_native_bridge_macos","dependencies":[]},{"name":"quill_native_bridge_web","dependencies":[]},{"name":"quill_native_bridge_windows","dependencies":["file_selector_windows"]},{"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-07-30 16:44:38.240412","version":"3.32.8","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/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_ios-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_android-0.0.1+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_macos-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_linux-0.0.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_windows-0.0.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_analytics_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics_web-0.6.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core_web-3.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_web-0.0.2/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/ashwin/.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":"file_selector_linux","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_temp_fork","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"quill_native_bridge","dependencies":["quill_native_bridge_android","quill_native_bridge_web","quill_native_bridge_windows","quill_native_bridge_linux","quill_native_bridge_ios","quill_native_bridge_macos"]},{"name":"quill_native_bridge_android","dependencies":[]},{"name":"quill_native_bridge_ios","dependencies":[]},{"name":"quill_native_bridge_linux","dependencies":["file_selector_linux"]},{"name":"quill_native_bridge_macos","dependencies":[]},{"name":"quill_native_bridge_web","dependencies":[]},{"name":"quill_native_bridge_windows","dependencies":["file_selector_windows"]},{"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-07-30 17:23:14.904919","version":"3.32.8","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e02131e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,138 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +BottleCRM Mobile is a Flutter-based CRM application for startups and enterprises. The app follows a modular architecture with consistent patterns across CRM entities (Accounts, Contacts, Leads, Opportunities, Cases, Tasks, Events, Documents, Teams, Users, Invoices). + +## Build & Development Commands + +```bash +# Clean and prepare +flutter clean +flutter pub get + +# Build for release +flutter build appbundle # Android App Bundle for Play Store +flutter build apk # Android APK + +# Development +flutter run # Run in debug mode +flutter test # Run tests +``` + +## Architecture Overview + +### State Management +- **Pattern**: Custom BLoC-like pattern with singleton instances +- **Location**: `lib/bloc/` directory +- **Key Blocs**: `authBloc`, `dashboardBloc`, and module-specific blocs +- **Access**: Global singleton instances (e.g., `AuthBloc().getInstance()`) + +### API Layer +- **Base Service**: `CrmService` in `lib/services/crm_services.dart` +- **Configuration**: Environment-based API URLs via `lib/config/api_config.dart` + - **Development**: `http://localhost:3000/` (debug builds) + - **Production**: `https://api.bottlecrm.io/api/` (release builds) +- **Authentication**: JWT token-based with SharedPreferences storage +- **Google OAuth**: Integrated with `google_sign_in` package +- **Multi-tenancy**: Organization header support + +### Navigation +- **Pattern**: Named routes defined in `main.dart` +- **Home Screen**: Login screen (no splash screen) +- **Bottom Navigation**: 5 tabs for main app sections + +### Module Structure +Each CRM module follows a consistent pattern: +``` +lib/ui/screens/{module}/ +├── {module}_list.dart # List/index view +├── {module}_create.dart # Create new entity +└── {module}_details.dart # View/edit entity +``` + +Available modules: accounts, contacts, leads, opportunities, cases, tasks, events, documents, teams, users, invoices + +### Responsive Design +- **Helper**: `lib/responsive.dart` +- **Breakpoints**: Mobile (<650px), Tablet (650-1100px), Desktop (>1100px) +- **Usage**: `Responsive.isMobile(context)`, `Responsive.isTablet(context)`, `Responsive.isDesktop(context)` + +## Key Files & Directories + +- **Entry Point**: `lib/main.dart` - Contains all route definitions and app configuration +- **Models**: `lib/model/` - Dart classes for CRM entities +- **Services**: `lib/services/` - API communication and network layer +- **Configuration**: `lib/config/` - API URLs and environment configuration +- **Widgets**: `lib/ui/widgets/` - Reusable UI components +- **Utils**: `lib/utils/` - Validation helpers and utilities +- **Assets**: `assets/images/` - SVG icons and images for each module + +## Development Patterns + +### Adding New Routes +Add routes to the `routes` map in `main.dart`: +```dart +'/new-screen': (context) => NewScreen(), +``` + +### Creating New Modules +1. Create model in `lib/model/` +2. Create bloc in `lib/bloc/` +3. Create screens following the pattern: `{module}_list.dart`, `{module}_create.dart`, `{module}_details.dart` +4. Add API methods to `CrmService` +5. Add routes in `main.dart` + +### API Integration +Extend `CrmService` class with new methods. Use the established pattern: +```dart +Future> getEntities() async { + // Implementation follows existing pattern +} +``` + +### UI Styling +- **Primary Color**: `#3E79F7` (blue) +- **Background**: `#ECEEF4` (light gray) +- **Custom Widgets**: Use existing widgets like `DashboardCountCard`, `RecentCardWidget` + +## Configuration Notes + +- **Firebase**: Integrated for analytics (configuration in `android/app/google-services.json`) +- **Android**: Min SDK 23, Target SDK 35 +- **iOS**: Deployment target 11.0 +- **Dependencies**: Key packages include `flutter_svg`, `http`, `shared_preferences`, `firebase_core`, `connectivity_plus`, `file_picker`, `flutter_quill`, `google_sign_in` + +## Google Sign-In Configuration + +### Android Setup +- **SHA-1 Fingerprint**: `67:C4:BE:5A:97:39:47:0B:40:2C:14:05:F1:81:AB:C7:E6:CF:A7:DF` +- **Package Name**: `io.bottlecrm` +- **Google Services**: Configured in `android/app/google-services.json` +- **OAuth Client**: Android client type with SHA-1 certificate hash + +### API Integration +- **Endpoint**: `/auth/google-login/` +- **Method**: POST with `id_token` parameter +- **Flow**: Google OAuth → ID Token → Backend verification → JWT token + +### Environment Configuration +Use `ApiConfig` class to manage different API URLs: +```dart +// Check current environment +ApiConfig.getCurrentEnvironment(); // "Development" or "Production" + +// Get current API URL +ApiConfig.getApiUrl(); + +// Override API URL (optional) +ApiConfig.setApiUrl('https://custom-api.com/api/'); +``` + +## Testing + +- **Location**: `test/` directory +- **Focus**: Authentication and validation testing +- **Command**: `flutter test` \ No newline at end of file diff --git a/README.md b/README.md index c100630..f9cb046 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,120 @@ -# BottleCRM +# BottleCRM Mobile -Free CRM for startups and enterprises. +A Flutter-based mobile CRM application for startups and enterprises. This app provides comprehensive customer relationship management features including account management, lead tracking, opportunity pipeline, task management, and more. + +## Features + +- **Google Sign-In**: Secure OAuth-based authentication +- **Dashboard**: Overview of CRM metrics and recent activities +- **Accounts**: Customer account management +- **Contacts**: Contact information and communication history +- **Leads**: Lead tracking and conversion pipeline +- **Opportunities**: Sales opportunity management +- **Cases**: Customer support case tracking +- **Tasks**: Task management and assignments +- **Events**: Calendar and event scheduling +- **Documents**: File management and sharing +- **Teams**: Team collaboration tools +- **Users**: User management and permissions +- **Invoices**: Billing and invoice generation + +## Requirements + +- Flutter SDK 3.32.8 or later +- Dart SDK 3.0.0 or later +- Android SDK (API level 23+) +- iOS 11.0+ (for iOS builds) + +## Getting Started + +### Installation + +1. Clone the repository: +```bash +git clone +cd bottlecrm_mobile +``` +2. Install dependencies: +```bash +flutter pub get +``` + +3. Configure Google Sign-In: + - Add your `google-services.json` to `android/app/` + - Configure Google Cloud Console with SHA-1 fingerprint + - Set up OAuth consent screen + +### Development + +```bash +# Run the app in debug mode +flutter run -# build +# Run tests +flutter test + +# Analyze code +flutter analyze +``` + +### Build + +```bash +# Clean previous builds flutter clean flutter pub get -flutter build appbundle -flutter build apk + +# Build for Android +flutter build appbundle # For Play Store +flutter build apk # For direct installation + +# Build for iOS (macOS only) +flutter build ios +``` + +## Architecture + +The app follows a modular architecture with: + +- **Custom BLoC Pattern**: State management using singleton BLoC instances +- **Modular Structure**: Consistent patterns across all CRM modules +- **Responsive Design**: Adaptive UI for mobile, tablet, and desktop +- **API Integration**: RESTful API communication with JWT authentication + +For detailed architecture information, see [CLAUDE.md](CLAUDE.md). + +## Configuration + +### API Configuration +The app uses environment-based API URLs: +- **Development**: `http://localhost:3000/` (debug builds) +- **Production**: `https://api.bottlecrm.io/api/` (release builds) + +### Authentication +- **Google OAuth**: Primary authentication method +- **JWT Tokens**: Backend authentication after Google sign-in +- **Storage**: SharedPreferences for local token storage + +### Google Sign-In Setup + +1. **Get SHA-1 fingerprint**: + ```bash + cd android + ./gradlew signingReport + ``` + +2. **Google Cloud Console**: + - Create OAuth 2.0 Client ID for Android + +3. **Firebase Console**: + - Enable Google Sign-In provider + - Download updated `google-services.json` + +### Multi-tenancy +- Organization-based data isolation +- Organization header support in API requests + +## License + +Free CRM for startups and enterprises. diff --git a/android/app/google-services.json b/android/app/google-services.json index 642c4df..4f90de3 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -1,33 +1,41 @@ { "project_info": { - "project_number": "74115878447", - "project_id": "bottle-crm-10074", - "storage_bucket": "bottle-crm-10074.appspot.com" + "project_number": "1072513761792", + "project_id": "bottlecrm-io", + "storage_bucket": "bottlecrm-io.firebasestorage.app" }, "client": [ { "client_info": { - "mobilesdk_app_id": "1:74115878447:android:858fb769df26bb2c5900da", + "mobilesdk_app_id": "1:1072513761792:android:aa69724adcb7121fd74ee5", "android_client_info": { "package_name": "io.bottlecrm" } }, "oauth_client": [ { - "client_id": "74115878447-0r10i3hk3mma0u2vaenbsbtvvtud5sv5.apps.googleusercontent.com", + "client_id": "1072513761792-raut9sdi00i87j81o4irmiha3fd5pmvc.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "io.bottlecrm", + "certificate_hash": "67c4be5a9739470b402c1405f181abc7e6cfa7df" + } + }, + { + "client_id": "1072513761792-e0qm5a5gsghr05elfcm8esjtu2v6d4f3.apps.googleusercontent.com", "client_type": 3 } ], "api_key": [ { - "current_key": "AIzaSyD8es-uwk_IlZsuHWlEwfiEZfsrENKXRgA" + "current_key": "AIzaSyDsA2wgQIw-bVgwODNMIF482gVRn5xdANU" } ], "services": { "appinvite_service": { "other_platform_oauth_client": [ { - "client_id": "74115878447-0r10i3hk3mma0u2vaenbsbtvvtud5sv5.apps.googleusercontent.com", + "client_id": "1072513761792-e0qm5a5gsghr05elfcm8esjtu2v6d4f3.apps.googleusercontent.com", "client_type": 3 } ] diff --git a/lib/bloc/auth_bloc.dart b/lib/bloc/auth_bloc.dart index 2319b1a..3f57df3 100644 --- a/lib/bloc/auth_bloc.dart +++ b/lib/bloc/auth_bloc.dart @@ -4,6 +4,7 @@ import 'package:bottle_crm/model/organization.dart'; import 'package:bottle_crm/model/profile.dart'; import 'package:bottle_crm/services/crm_services.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:google_sign_in/google_sign_in.dart'; class AuthBloc { String? _subDomainName; @@ -53,12 +54,33 @@ class AuthBloc { return result; } - Future login(data) async { + Future googleLogin() async { try { Map result = {}; final SharedPreferences preferences = await SharedPreferences.getInstance(); - await CrmService().userLogin(data).then((response) async { + + // Initialize Google Sign-In + final GoogleSignIn googleSignIn = GoogleSignIn( + scopes: ['email', 'profile'], + ); + + // Sign in with Google + final GoogleSignInAccount? googleUser = await googleSignIn.signIn(); + if (googleUser == null) { + return {"error": true, "message": "Google sign-in was cancelled"}; + } + + // Get authentication details + final GoogleSignInAuthentication googleAuth = await googleUser.authentication; + final String? idToken = googleAuth.idToken; + + if (idToken == null) { + return {"error": true, "message": "Failed to get Google ID token"}; + } + + // Send token to backend + await CrmService().googleLogin(idToken).then((response) async { var res = (json.decode(response.body)); if (res['error'] == false) { _authToken = "JWT " + res['token']; @@ -68,11 +90,14 @@ class AuthBloc { result = res; } }).catchError((onError) { - print("login error>> $onError"); - result = {"status": "error", "message": onError}; + print("google login error>> $onError"); + result = {"error": true, "message": "Network Error, check your internet"}; }); return result; - } catch (e) {} + } catch (e) { + print("google login error>> $e"); + return {"error": true, "message": "Google login failed. Please try again."}; + } } Future forgotPassword(data) async { diff --git a/lib/config/api_config.dart b/lib/config/api_config.dart new file mode 100644 index 0000000..44e6253 --- /dev/null +++ b/lib/config/api_config.dart @@ -0,0 +1,41 @@ +import 'package:flutter/foundation.dart'; + +class ApiConfig { + // Environment-based API URLs + static const String DEV_API_URL = 'http://localhost:3000/'; + static const String PROD_API_URL = 'https://api.bottlecrm.io/api/'; + + // Available APIs for manual switching + static const List AVAILABLE_APIS = [ + DEV_API_URL, + PROD_API_URL, + ]; + + // Current API URL (can be changed at runtime) + static String? _currentApiUrl; + + static void setApiUrl(String url) { + _currentApiUrl = url.endsWith('/') ? url : '$url/'; + } + + static String getApiUrl() { + if (_currentApiUrl != null) { + return _currentApiUrl!; + } + + // Auto-select based on build mode + if (kDebugMode) { + return DEV_API_URL; // Development/Debug builds + } else { + return PROD_API_URL; // Production/Release builds + } + } + + static bool isDebugMode() { + return kDebugMode; + } + + static String getCurrentEnvironment() { + return kDebugMode ? 'Development' : 'Production'; + } +} \ No newline at end of file diff --git a/lib/services/crm_services.dart b/lib/services/crm_services.dart index facd7a5..9cda979 100644 --- a/lib/services/crm_services.dart +++ b/lib/services/crm_services.dart @@ -7,15 +7,20 @@ import 'package:http/http.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'package:bottle_crm/ui/screens/http_excepion.dart'; +import 'package:bottle_crm/config/api_config.dart'; import 'network_services.dart'; class CrmService { NetworkService networkService = NetworkService(); - // final baseUrl = 'https://bottlecrm.com/api/'; - final baseUrl = 'https://api.bottle-dev.com/api/'; + String baseUrl = ApiConfig.getApiUrl(); Map _headers = {}; + // Method to set custom API URL + void setBaseUrl(String url) { + baseUrl = url.endsWith('/') ? url : '$url/'; + } + updateHeaders() async { final SharedPreferences preferences = await SharedPreferences.getInstance(); _headers['Authorization'] = preferences.getString('authToken'); @@ -41,10 +46,10 @@ class CrmService { } } - Future userLogin(body) async { + Future googleLogin(String idToken) async { try { - return await networkService.post(Uri.parse(baseUrl + 'auth/login/'), - body: body); + return await networkService.post(Uri.parse(baseUrl + 'auth/google-login/'), + body: {'id_token': idToken}); } on SocketException { throw HttpException("Network Error, check your internet"); } on FormatException { diff --git a/lib/ui/screens/authentication/login.dart b/lib/ui/screens/authentication/login.dart index 30b666c..3e92708 100644 --- a/lib/ui/screens/authentication/login.dart +++ b/lib/ui/screens/authentication/login.dart @@ -1,5 +1,4 @@ import 'package:bottle_crm/responsive.dart'; -import 'package:bottle_crm/utils/validations.dart'; import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:flutter/material.dart'; @@ -15,9 +14,6 @@ class Login extends StatefulWidget { } class _LoginState extends State { - final GlobalKey _loginFormKey = GlobalKey(); - bool _isPasswordVisible = false; - Map _loginFormData = {"email": "", "password": ""}; bool _isLoading = false; String _errorMessage = ''; @@ -26,62 +22,38 @@ class _LoginState extends State { super.initState(); } - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - borderSide: BorderSide(width: 1, color: Colors.black12), - ); - } - _submitForm() async { - if (!_loginFormKey.currentState!.validate()) { - return; - } - _loginFormKey.currentState!.save(); + _googleLogin() async { setState(() { _isLoading = true; }); - Map result = {}; - result = await authBloc.login(_loginFormData); - if (result['error'] == false) { - setState(() { - _errorMessage = ''; - }); - await authBloc.fetchCompanies(); - await FirebaseAnalytics.instance.logEvent(name: "login"); - Navigator.pushNamedAndRemoveUntil( - context, '/companies_List', (route) => false); - } else if (result['error'] == true) { - setState(() { - _errorMessage = result['errors']; - }); - } else { + + try { + Map result = await authBloc.googleLogin(); + if (result['error'] == false) { + setState(() { + _errorMessage = ''; + }); + await authBloc.fetchCompanies(); + await FirebaseAnalytics.instance.logEvent(name: "google_login"); + Navigator.pushNamedAndRemoveUntil( + context, '/companies_List', (route) => false); + } else { + setState(() { + _errorMessage = result['message'] ?? 'Google login failed'; + }); + } + } catch (e) { setState(() { - _errorMessage = ''; + _errorMessage = 'Google login failed. Please try again.'; }); - showErrorMessage(context, result['message'].toString()); } + setState(() { _isLoading = false; }); } - showErrorMessage(BuildContext context, String message) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(message), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } Widget loginWidget() { return Responsive( @@ -92,532 +64,415 @@ class _LoginState extends State { buildMobileScreen() { return SingleChildScrollView( - child: Column( - children: [ - SizedBox(height: screenHeight * 0.1), - Container( - decoration: BoxDecoration( - color: Colors.white, - ), - width: screenWidth, - height: screenHeight, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0), + child: Container( + height: screenHeight, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Theme.of(context).primaryColor, + Theme.of(context).primaryColor.withOpacity(0.8), + ], + ), + ), + child: Column( + children: [ + SizedBox(height: screenHeight * 0.08), + // Logo and Branding Section + Container( + padding: EdgeInsets.symmetric(horizontal: 30.0), child: Column( - mainAxisAlignment: MainAxisAlignment.start, children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Login', - style: TextStyle( - color: Color.fromARGB(255, 59, 59, 59), - fontWeight: FontWeight.bold, - fontSize: screenWidth / 15), - ), - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.3, - ) - ], + SvgPicture.asset( + 'assets/images/logo.svg', + width: screenWidth * 0.4, + color: Colors.white, + ), + SizedBox(height: 20), + Text( + 'BottleCRM', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 10, + fontWeight: FontWeight.bold, + letterSpacing: 1.2, ), ), - SizedBox( - height: screenHeight * 0.05, + SizedBox(height: 10), + Text( + 'Free CRM for startups and enterprises', + style: TextStyle( + color: Colors.white.withOpacity(0.9), + fontSize: screenWidth / 25, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.center, ), - Container( - child: Form( - key: _loginFormKey, - child: Column( - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Email ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.email_outlined, - color: Theme.of(context) - .primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.emailAddress, - validator: (value) => - FieldValidators.emailFieldValidation( - value!), - onSaved: (value) { - _loginFormData['email'] = value; - }, - ), - ), - ], + ], + ), + ), + SizedBox(height: screenHeight * 0.08), + // Login Card + Expanded( + child: Container( + width: screenWidth, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + offset: Offset(0, -5), + ), + ], + ), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Welcome Back!', + style: TextStyle( + color: Colors.black87, + fontSize: screenWidth / 12, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 10), + Text( + 'Sign in to continue managing your business', + style: TextStyle( + color: Colors.grey[600], + fontSize: screenWidth / 26, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: screenHeight * 0.05), + _errorMessage != '' + ? Container( + margin: EdgeInsets.only(bottom: 20.0), + padding: EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.red.withOpacity(0.3)), ), - ), - SizedBox(height: screenHeight * 0.02), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Password ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: - _isPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context) - .primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isPasswordVisible = - !_isPasswordVisible; - }); - }, - icon: Icon( - _isPasswordVisible - ? Icons - .visibility_outlined - : Icons - .visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) => - FieldValidators.passwordValidation( - value!), - onSaved: (value) { - _loginFormData['password'] = value; - }, + Icon(Icons.error_outline, color: Colors.red, size: 20), + SizedBox(width: 8), + Expanded( + child: Text( + _errorMessage, + style: TextStyle( + color: Colors.red[700], + fontSize: screenWidth / 30, + ), ), ), ], ), - ), - _errorMessage != '' - ? Container( - child: Text( - _errorMessage, + ) + : SizedBox(), + !_isLoading + ? Container( + width: screenWidth, + height: 56, + child: ElevatedButton( + onPressed: _googleLogin, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black87, + elevation: 2, + shadowColor: Colors.black26, + side: BorderSide(color: Colors.grey[300]!, width: 1), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/google-icon.png', + width: 24, + height: 24, + ), + SizedBox(width: 16), + Text( + 'Continue with Google', style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), + fontSize: screenWidth / 22, + fontWeight: FontWeight.w600, + ), ), - ) - : SizedBox( - height: 0.0, - ), - GestureDetector( - onTap: () { - Navigator.pushNamed( - context, '/forgot_password'); - }, - child: Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - alignment: Alignment.centerRight, - child: Text( - 'Forgot Password?', - style: TextStyle( - color: Colors.blueAccent, - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500), + ], + ), + ), + ) + : Container( + height: 56, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + Theme.of(context).primaryColor), ), ), ), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - 'Login', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 22), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: - new AlwaysStoppedAnimation( - Color.fromRGBO( - 62, 121, 247, 1))), - ) - ], - )), - ), - Container( - margin: EdgeInsets.symmetric(vertical: 20.0), - child: Text( - ' Or Connect With ', - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 24), - ), - ), - Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey[400]!), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: GestureDetector( - onTap: () {}, + SizedBox(height: screenHeight * 0.04), + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.withOpacity(0.2)), + ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, children: [ - Image.asset('assets/images/google-icon.png', - width: screenWidth / 18), - SizedBox(width: 8.0), - Text( - 'Login With Google', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 24, - fontWeight: FontWeight.w600), - ) + Icon(Icons.info_outline, color: Colors.blue, size: 20), + SizedBox(width: 8), + Expanded( + child: Text( + 'Secure sign-in powered by Google OAuth 2.0', + style: TextStyle( + color: Colors.blue[700], + fontSize: screenWidth / 32, + ), + ), + ), ], - )), - ), + ), + ), SizedBox( height: screenHeight * 0.05, ), - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Don't have an account yet? ", - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 24), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/register'); - }, - child: Text( - 'Sign Up', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontSize: screenWidth / 24), - ), - ) ], - )) - ], + ), + ), ), ), - ), - ], + ], + ), ), ); } buildTabletScreen() { return Container( + height: screenHeight, decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topLeft: Radius.circular(50.0))), - height: screenHeight * 0.9, - width: screenWidth, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0), - child: Column( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Theme.of(context).primaryColor, + Theme.of(context).primaryColor, + ], + ), + ), + child: Row( + children: [ + // Left side - Branding + Expanded( + flex: 1, + child: Container( + padding: EdgeInsets.all(40), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ + SvgPicture.asset( + 'assets/images/logo.svg', + width: screenWidth * 0.15, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), + SizedBox(height: 30), Text( - 'Login', + 'BottleCRM', style: TextStyle( - color: Colors.black54, fontSize: screenWidth / 24), + color: Colors.white, + fontSize: screenWidth / 20, + fontWeight: FontWeight.bold, + letterSpacing: 1.2, + ), + ), + SizedBox(height: 15), + Text( + 'Free CRM for startups and enterprises', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 50, + fontWeight: FontWeight.w400, + height: 1.5, + ), + ), + SizedBox(height: 30), + Text( + 'Manage your customers, leads, and opportunities all in one place.', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 60, + height: 1.6, + ), ), - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.2, - ) ], ), ), - SizedBox( - height: screenHeight * 0.1, - ), - Container( - width: screenWidth * 0.5, - child: Form( - key: _loginFormKey, - child: Column( - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Email', - style: TextStyle( - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.email_outlined, - color: Theme.of(context).primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _loginFormData['email'] = value; - }, + ), + // Right side - Login Form + Expanded( + flex: 1, + child: Container( + margin: EdgeInsets.all(40), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 20, + offset: Offset(0, 10), + ), + ], + ), + child: Container( + padding: EdgeInsets.all(40), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Welcome Back!', + style: TextStyle( + color: Colors.black87, + fontSize: screenWidth / 25, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 10), + Text( + 'Sign in to continue managing your business', + style: TextStyle( + color: Colors.grey[600], + fontSize: screenWidth / 55, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 40), + _errorMessage != '' + ? Container( + margin: EdgeInsets.only(bottom: 20.0), + padding: EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.red.shade50, + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.red.shade200), + ), + child: Row( + children: [ + Icon(Icons.error_outline, color: Colors.red, size: 18), + SizedBox(width: 8), + Expanded( + child: Text( + _errorMessage, + style: TextStyle( + color: Colors.red[700], + fontSize: screenWidth / 60, + ), + ), + ), + ], + ), + ) + : SizedBox(), + !_isLoading + ? Container( + width: double.infinity, + height: 56, + child: ElevatedButton( + onPressed: _googleLogin, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black87, + elevation: 2, + shadowColor: Colors.black26, + side: BorderSide(color: Colors.grey[300]!, width: 1), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/google-icon.png', + width: 24, + height: 24, + ), + SizedBox(width: 16), + Text( + 'Continue with Google', + style: TextStyle( + fontSize: screenWidth / 45, + fontWeight: FontWeight.w600, + ), + ), + ], ), ), - ], - ), - ), - SizedBox(height: screenHeight * 0.02), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Password', - style: TextStyle( - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: _isPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context).primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isPasswordVisible = - !_isPasswordVisible; - }); - }, - icon: Icon( - _isPasswordVisible - ? Icons.visibility_outlined - : Icons.visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _loginFormData['password'] = value; - }, + ) + : Container( + height: 56, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + Theme.of(context).primaryColor), ), ), - ], - ), + ), + SizedBox(height: 30), + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.shade200), ), - _errorMessage != '' - ? Container( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 45), + child: Row( + children: [ + Icon(Icons.info_outline, color: Colors.blue, size: 18), + SizedBox(width: 8), + Expanded( + child: Text( + 'Secure sign-in powered by Google OAuth 2.0', + style: TextStyle( + color: Colors.blue[700], + fontSize: screenWidth / 65, ), - ) - : Container(), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/forgot_password'); - }, - child: Container( - margin: EdgeInsets.symmetric(vertical: 20.0), - alignment: Alignment.centerRight, - child: Text( - 'Forgot Password?', - style: TextStyle( - color: Colors.black54, - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500), + ), ), - ), + ], ), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - _errorMessage = ''; - _submitForm(); - }, - child: Text( - 'Sign In', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 35), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: new AlwaysStoppedAnimation( - Color.fromRGBO(62, 121, 247, 1))), - ) - ], - )), - ), - Container( - width: screenWidth * 0.5, - margin: EdgeInsets.symmetric(vertical: 20.0), - child: Text( - '-------------- Or Connect With --------------', - style: - TextStyle(color: Colors.grey, fontSize: screenWidth / 45), - ), - ), - Container( - width: screenWidth * 0.5, - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey[400]!), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: GestureDetector( - onTap: () {}, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('assets/images/google-icon.png', - width: screenWidth / 25), - SizedBox(width: 8.0), - Text( - 'Sign In With Google', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 40, - fontWeight: FontWeight.w600), - ) - ], - )), - ), - SizedBox( - height: screenHeight * 0.2, - ), - Container( - width: screenWidth * 0.5, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Don't have an account yet? ", - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 40), ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/register'); - }, - child: Text( - 'Sign Up', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontSize: screenWidth / 40), - ), - ) ], - )) - ], - ), + ), + ), + ), + ), + ], ), ); } @@ -627,9 +482,7 @@ class _LoginState extends State { screenWidth = MediaQuery.of(context).size.width; screenHeight = MediaQuery.of(context).size.height; return Scaffold( - body: Container( - decoration: BoxDecoration(color: Color.fromARGB(226, 73, 128, 255)), - child: loginWidget()), + body: loginWidget(), ); } } diff --git a/pubspec.yaml b/pubspec.yaml index ffae55f..157c967 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: firebase_analytics: ^12.0.0 firebase_core: ^4.0.0 flutter_swipe_detector: ^2.0.0 + google_sign_in: ^6.2.2 flutter_icons: diff --git a/test/widget_test.dart b/test/widget_test.dart index 18a56a6..d130c5b 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -12,13 +12,13 @@ import 'package:flutter_test/flutter_test.dart'; // import 'package:mobile2/main.dart'; void main() { - group("Login Page", () { - test("Email should Not be Empty", () async{ - Map result = await authBloc.login({"email": "", "password": ""}); - expect(true, result['error']); + group("Google Login", () { + test("Google Login should handle authentication", () async{ + Map result = await authBloc.googleLogin(); + expect(result.containsKey('error'), true); }); - test("Password should Not be Empty", () { + test("Password validation should still work", () { var result = FieldValidators.passwordValidation(""); expect("Please Enter Password", result); }); From e8baa5b1e47a43c49062101cc223fe61215441ea Mon Sep 17 00:00:00 2001 From: Ashwin Date: Wed, 30 Jul 2025 21:18:47 +0530 Subject: [PATCH 2/9] fix: Update API URLs for development and production environments; enhance Google login response handling and logging --- CLAUDE.md | 4 +- README.md | 4 +- lib/bloc/auth_bloc.dart | 12 +- lib/config/api_config.dart | 4 +- lib/services/crm_services.dart | 9 +- lib/services/network_services.dart | 80 +- lib/ui/screens/tasks/task_create.dart.bak | 867 ---------------------- 7 files changed, 96 insertions(+), 884 deletions(-) delete mode 100644 lib/ui/screens/tasks/task_create.dart.bak diff --git a/CLAUDE.md b/CLAUDE.md index e02131e..d8f3f82 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,8 +33,8 @@ flutter test # Run tests ### API Layer - **Base Service**: `CrmService` in `lib/services/crm_services.dart` - **Configuration**: Environment-based API URLs via `lib/config/api_config.dart` - - **Development**: `http://localhost:3000/` (debug builds) - - **Production**: `https://api.bottlecrm.io/api/` (release builds) + - **Development**: `http://localhost:3001/` (debug builds) + - **Production**: `https://api.bottlecrm.io/` (release builds) - **Authentication**: JWT token-based with SharedPreferences storage - **Google OAuth**: Integrated with `google_sign_in` package - **Multi-tenancy**: Organization header support diff --git a/README.md b/README.md index f9cb046..49d832a 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,8 @@ For detailed architecture information, see [CLAUDE.md](CLAUDE.md). ### API Configuration The app uses environment-based API URLs: -- **Development**: `http://localhost:3000/` (debug builds) -- **Production**: `https://api.bottlecrm.io/api/` (release builds) +- **Development**: `http://localhost:3001/` (debug builds) +- **Production**: `https://api.bottlecrm.io/` (release builds) ### Authentication - **Google OAuth**: Primary authentication method diff --git a/lib/bloc/auth_bloc.dart b/lib/bloc/auth_bloc.dart index 3f57df3..78b480b 100644 --- a/lib/bloc/auth_bloc.dart +++ b/lib/bloc/auth_bloc.dart @@ -82,12 +82,18 @@ class AuthBloc { // Send token to backend await CrmService().googleLogin(idToken).then((response) async { var res = (json.decode(response.body)); - if (res['error'] == false) { + if (response.statusCode == 200 && res['token'] != null) { _authToken = "JWT " + res['token']; preferences.setString("authToken", _authToken!); - result = res; + + // Store user profile data if available + if (res['user'] != null) { + _userProfile = Profile.fromJson(res['user']); + } + + result = {"error": false, "token": res['token'], "user": res['user']}; } else { - result = res; + result = {"error": true, "message": res['message'] ?? "Login failed"}; } }).catchError((onError) { print("google login error>> $onError"); diff --git a/lib/config/api_config.dart b/lib/config/api_config.dart index 44e6253..d036259 100644 --- a/lib/config/api_config.dart +++ b/lib/config/api_config.dart @@ -2,8 +2,8 @@ import 'package:flutter/foundation.dart'; class ApiConfig { // Environment-based API URLs - static const String DEV_API_URL = 'http://localhost:3000/'; - static const String PROD_API_URL = 'https://api.bottlecrm.io/api/'; + static const String DEV_API_URL = 'http://localhost:3001/'; + static const String PROD_API_URL = 'https://api.bottlecrm.io/'; // Available APIs for manual switching static const List AVAILABLE_APIS = [ diff --git a/lib/services/crm_services.dart b/lib/services/crm_services.dart index 9cda979..5f5c484 100644 --- a/lib/services/crm_services.dart +++ b/lib/services/crm_services.dart @@ -1,5 +1,6 @@ // import 'package:bottle_crm/bloc/setting_bloc.dart'; // import 'package:bottle_crm/model/document.dart'; +import 'dart:convert'; import 'dart:io'; import 'package:file_picker/file_picker.dart'; @@ -48,8 +49,12 @@ class CrmService { Future googleLogin(String idToken) async { try { - return await networkService.post(Uri.parse(baseUrl + 'auth/google-login/'), - body: {'id_token': idToken}); + Map headers = { + 'Content-Type': 'application/json', + }; + return await networkService.post(Uri.parse(baseUrl + 'auth/google'), + headers: headers, + body: jsonEncode({'idToken': idToken})); } on SocketException { throw HttpException("Network Error, check your internet"); } on FormatException { diff --git a/lib/services/network_services.dart b/lib/services/network_services.dart index fa4630a..2301ca4 100644 --- a/lib/services/network_services.dart +++ b/lib/services/network_services.dart @@ -11,16 +11,43 @@ class NetworkService { NetworkService.internal(); + // Helper method to print long strings in chunks + void _printLongString(String title, String content) { + const int chunkSize = 800; + print(title); + if (content.length <= chunkSize) { + print(content); + } else { + for (int i = 0; i < content.length; i += chunkSize) { + int endIndex = (i + chunkSize < content.length) ? i + chunkSize : content.length; + print("${content.substring(i, endIndex)}"); + } + } + } + Future get(var url, {Map? headers}) async { try { + // Log request details + print("=== GET REQUEST ==="); + print("URL: $url"); + print("Headers: $headers"); + print("=================="); + return client.get(url, headers: headers).then((http.Response response) { + // Log response details + print("=== GET RESPONSE ==="); + print("Status Code: ${response.statusCode}"); + print("Response Headers: ${response.headers}"); + _printLongString("Response Body:", response.body); + print("==================="); + return handleResponse(response); }); } on SocketException { - print("=======socket exceptiom"); + print("=======Socket Exception"); throw HttpException("Network Error, check your internet"); } catch (e) { - print("=======ache"); + print("=======Exception: $e"); throw HttpException("Something Went Wrong"); } finally { // client.close(); @@ -30,20 +57,34 @@ class NetworkService { Future post(Uri url, {Map? headers, body, encoding}) { try { + // Log request details + print("=== POST REQUEST ==="); + print("URL: $url"); + print("Headers: $headers"); + _printLongString("Body:", body?.toString() ?? "null"); + print("=================="); + return client .post(url, headers: headers, body: body, encoding: encoding) .then((http.Response response) { + // Log response details + print("=== POST RESPONSE ==="); + print("Status Code: ${response.statusCode}"); + print("Response Headers: ${response.headers}"); + _printLongString("Response Body:", response.body); + print("===================="); + return handleResponse(response); }); } on FormatException { - print("=========Format Excepion"); + print("=========Format Exception"); throw HttpException("Server issue"); } on SocketException { - print("=======socket exceptiom"); + print("=======Socket Exception"); throw HttpException("Network Error, check your internet"); } catch (e) { - print("=======ache"); - throw HttpException("Something Went Wrongggg"); + print("=======Exception: $e"); + throw HttpException("Something Went Wrong"); } finally { // client.close(); } @@ -52,9 +93,23 @@ class NetworkService { Future put(Uri url, {Map? headers, body, encoding}) { try { + // Log request details + print("=== PUT REQUEST ==="); + print("URL: $url"); + print("Headers: $headers"); + _printLongString("Body:", body?.toString() ?? "null"); + print("=================="); + return client .put(url, headers: headers, body: body, encoding: encoding) .then((http.Response response) { + // Log response details + print("=== PUT RESPONSE ==="); + print("Status Code: ${response.statusCode}"); + print("Response Headers: ${response.headers}"); + _printLongString("Response Body:", response.body); + print("==================="); + return handleResponse(response); }); } finally { @@ -64,9 +119,22 @@ class NetworkService { Future delete(Uri url, {Map? headers}) { try { + // Log request details + print("=== DELETE REQUEST ==="); + print("URL: $url"); + print("Headers: $headers"); + print("====================="); + return client .delete(url, headers: headers) .then((http.Response response) { + // Log response details + print("=== DELETE RESPONSE ==="); + print("Status Code: ${response.statusCode}"); + print("Response Headers: ${response.headers}"); + _printLongString("Response Body:", response.body); + print("======================"); + return handleResponse(response); }); } finally { diff --git a/lib/ui/screens/tasks/task_create.dart.bak b/lib/ui/screens/tasks/task_create.dart.bak deleted file mode 100644 index e7d03fd..0000000 --- a/lib/ui/screens/tasks/task_create.dart.bak +++ /dev/null @@ -1,867 +0,0 @@ -import 'dart:io'; - -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/task_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; - -class CreateTask extends StatefulWidget { - CreateTask(); - @override - State createState() => _CreateTaskState(); -} - -class _CreateTaskState extends State { - final GlobalKey _taskFormKey = GlobalKey(); - TextEditingController _dateController = TextEditingController(); - TextEditingController fileNameController = new TextEditingController(); - String? selectedDate = ""; - DateTime initialDate = DateTime.now(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File? file = File(''); - List _taskFormKeys = [ - 'title', - 'status', - 'priority', - 'account', - 'contacts', - 'closed_on', - 'assigned_to', - 'teams', - ]; - - @override - void initState() { - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - super.initState(); - } - - _selectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: DateTime(1950), - lastDate: DateTime(2023), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildTaskBlock(); - } else if (_currentTabIndex == 1) { - return buildDescriptionBlock(); - } - } - - Positioned buildReqField() { - return Positioned( - child: Container( - width: 3.0, - color: Colors.red, - ), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildTaskBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _taskFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Task Title ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - taskBloc.currentEditTask!['title'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - taskBloc.currentEditTask!['title'] = value; - }, - ), - ), - _errors['title'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['title'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Account ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: taskBloc.accountsObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - taskBloc.currentEditTask!['account'] = ""; - } else { - taskBloc.currentEditTask!['account'] = - selection; - } - }, - selectedItem: - taskBloc.currentEditTask!['account'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a account", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['account'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['account'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Contacts", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: - taskBloc.currentEditTask!['contacts'], - onSaved: (value) { - if (value == null) return; - taskBloc.currentEditTask!['contacts'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Status ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: taskBloc.status!, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - taskBloc.currentEditTask!['status'] = ""; - } else { - taskBloc.currentEditTask!['status'] = - selection; - } - }, - selectedItem: - taskBloc.currentEditTask!['status'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Status", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['status'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['status'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Priority ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: taskBloc.priorities!, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - taskBloc.currentEditTask!['priority'] = ""; - } else { - taskBloc.currentEditTask!['priority'] = - selection; - } - }, - selectedItem: - taskBloc.currentEditTask!['priority'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Priority", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['priority'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['priority'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Due Date ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _dateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _selectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - taskBloc.currentEditTask!['due_date'] = value; - }, - ), - ), - _errors['due_date'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['due_date'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned to", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Assigned to", - ), - initialValue: taskBloc - .currentEditTask!['assigned_to'], - onSaved: (value) { - if (value == null) return; - taskBloc.currentEditTask!['assigned_to'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: - taskBloc.currentEditTask!['teams'], - onSaved: (value) { - if (value == null) return; - taskBloc.currentEditTask!['teams'] = - value; - })) - ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: SizedBox() - // Column( - // children: [ - // quill.QuillToolbar.basic( - // controller: _controller, - // showAlignmentButtons: true, - // showBackgroundColorButton: false, - // showCameraButton: false, - // showImageButton: false, - // showVideoButton: false, - // showDividers: false, - // showColorButton: false, - // showUndo: false, - // showRedo: false, - // showQuote: false, - // showClearFormat: false, - // showIndent: false, - // showLink: false, - // showCodeBlock: false, - // showInlineCode: false, - // showListCheck: false, - // ), - // Expanded( - // child: Container( - // child: quill.QuillEditor.basic( - // controller: _controller, - // readOnly: true, - // ), - // ), - // ) - // ], - // ) - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - taskBloc.cancelCurrentEditTask(); - taskBloc.currentEditTaskId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - taskBloc.currentEditTaskId == "" - ? 'Add Task' - : "Edit Task", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_taskFormKey.currentState != null) - _taskFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Task', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_taskFormKey.currentState != null) { - if (!_taskFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _taskFormKey.currentState!.save(); - // setState(() { - // _currentTabIndex = 1; - // }); - await Future.delayed(const Duration(seconds: 1), () async {}); - - Map _result = {}; - if (taskBloc.currentEditTaskId != null && - taskBloc.currentEditTaskId != "") { - _result = await taskBloc.editTask(); - } else { - _result = await taskBloc.createTask(); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - taskBloc.cancelCurrentEditTask(); - taskBloc.currentEditTaskId = ""; - showToaster(_result['message'], context); - taskBloc.tasks.clear(); - await taskBloc.fetchTasks(); - await FirebaseAnalytics.instance.logEvent(name: "task_Created"); - Navigator.pushReplacementNamed(context, '/tasks_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _taskFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} From 117b0b00eebea546ed2e86f31216ca3fd6d4bc77 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Wed, 30 Jul 2025 22:05:49 +0530 Subject: [PATCH 3/9] feat: Update Google login integration; modify API endpoint and response handling; enhance organization role display --- .flutter-plugins-dependencies | 2 +- CLAUDE.md | 4 +- android/app/google-services.json | 4 +- lib/bloc/auth_bloc.dart | 20 +++++-- lib/config/api_config.dart | 2 +- lib/model/organization.dart | 10 ++-- lib/services/crm_services.dart | 8 ++- .../authentication/companies_List.dart | 54 ++++++++++++++----- lib/ui/screens/authentication/login.dart | 1 - 9 files changed, 77 insertions(+), 28 deletions(-) diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 0ff1290..768e734 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/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_ios-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_android-0.0.1+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_macos-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_linux-0.0.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_windows-0.0.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_analytics_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics_web-0.6.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core_web-3.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_web-0.0.2/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/ashwin/.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":"file_selector_linux","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_temp_fork","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"quill_native_bridge","dependencies":["quill_native_bridge_android","quill_native_bridge_web","quill_native_bridge_windows","quill_native_bridge_linux","quill_native_bridge_ios","quill_native_bridge_macos"]},{"name":"quill_native_bridge_android","dependencies":[]},{"name":"quill_native_bridge_ios","dependencies":[]},{"name":"quill_native_bridge_linux","dependencies":["file_selector_linux"]},{"name":"quill_native_bridge_macos","dependencies":[]},{"name":"quill_native_bridge_web","dependencies":[]},{"name":"quill_native_bridge_windows","dependencies":["file_selector_windows"]},{"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-07-30 17:23:14.904919","version":"3.32.8","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/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_ios-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_android-0.0.1+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_macos-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_linux-0.0.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_windows-0.0.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_analytics_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics_web-0.6.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core_web-3.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_web-0.0.2/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/ashwin/.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":"file_selector_linux","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_temp_fork","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"quill_native_bridge","dependencies":["quill_native_bridge_android","quill_native_bridge_web","quill_native_bridge_windows","quill_native_bridge_linux","quill_native_bridge_ios","quill_native_bridge_macos"]},{"name":"quill_native_bridge_android","dependencies":[]},{"name":"quill_native_bridge_ios","dependencies":[]},{"name":"quill_native_bridge_linux","dependencies":["file_selector_linux"]},{"name":"quill_native_bridge_macos","dependencies":[]},{"name":"quill_native_bridge_web","dependencies":[]},{"name":"quill_native_bridge_windows","dependencies":["file_selector_windows"]},{"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-07-30 21:23:30.262984","version":"3.32.8","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index d8f3f82..d119746 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -114,8 +114,8 @@ Future> getEntities() async { - **OAuth Client**: Android client type with SHA-1 certificate hash ### API Integration -- **Endpoint**: `/auth/google-login/` -- **Method**: POST with `id_token` parameter +- **Endpoint**: `/auth/google/` +- **Method**: POST with `idToken` parameter - **Flow**: Google OAuth → ID Token → Backend verification → JWT token ### Environment Configuration diff --git a/android/app/google-services.json b/android/app/google-services.json index 4f90de3..b84d2a1 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -22,7 +22,7 @@ } }, { - "client_id": "1072513761792-e0qm5a5gsghr05elfcm8esjtu2v6d4f3.apps.googleusercontent.com", + "client_id": "1072513761792-dvcv8cj147oj6nav40u7jfjp1r3f0a1d.apps.googleusercontent.com", "client_type": 3 } ], @@ -35,7 +35,7 @@ "appinvite_service": { "other_platform_oauth_client": [ { - "client_id": "1072513761792-e0qm5a5gsghr05elfcm8esjtu2v6d4f3.apps.googleusercontent.com", + "client_id": "1072513761792-dvcv8cj147oj6nav40u7jfjp1r3f0a1d.apps.googleusercontent.com", "client_type": 3 } ] diff --git a/lib/bloc/auth_bloc.dart b/lib/bloc/auth_bloc.dart index 78b480b..095caf7 100644 --- a/lib/bloc/auth_bloc.dart +++ b/lib/bloc/auth_bloc.dart @@ -82,8 +82,13 @@ class AuthBloc { // Send token to backend await CrmService().googleLogin(idToken).then((response) async { var res = (json.decode(response.body)); - if (response.statusCode == 200 && res['token'] != null) { - _authToken = "JWT " + res['token']; + print("=== LOGIN RESPONSE DEBUG ==="); + print("Status Code: ${response.statusCode}"); + print("Response Body: ${response.body}"); + print("============================"); + + if (response.statusCode == 200 && res['success'] == true && res['JWTtoken'] != null) { + _authToken = "JWT " + res['JWTtoken']; preferences.setString("authToken", _authToken!); // Store user profile data if available @@ -91,7 +96,16 @@ class AuthBloc { _userProfile = Profile.fromJson(res['user']); } - result = {"error": false, "token": res['token'], "user": res['user']}; + // Store organizations list + if (res['organizations'] != null) { + _companies.clear(); + for (var org in res['organizations']) { + Organization organization = Organization.fromJson(org); + _companies.add(organization); + } + } + + result = {"error": false, "token": res['JWTtoken'], "user": res['user'], "organizations": res['organizations']}; } else { result = {"error": true, "message": res['message'] ?? "Login failed"}; } diff --git a/lib/config/api_config.dart b/lib/config/api_config.dart index d036259..f244280 100644 --- a/lib/config/api_config.dart +++ b/lib/config/api_config.dart @@ -2,7 +2,7 @@ import 'package:flutter/foundation.dart'; class ApiConfig { // Environment-based API URLs - static const String DEV_API_URL = 'http://localhost:3001/'; + static const String DEV_API_URL = 'http://192.168.0.106:3001/'; static const String PROD_API_URL = 'https://api.bottlecrm.io/'; // Available APIs for manual switching diff --git a/lib/model/organization.dart b/lib/model/organization.dart index 64acd5d..197c87f 100644 --- a/lib/model/organization.dart +++ b/lib/model/organization.dart @@ -1,15 +1,17 @@ class Organization { - int? id; + String? id; String? name; + String? role; - Organization({this.id, this.name}); + Organization({this.id, this.name, this.role}); Organization.fromJson(Map data) { - this.id = data['id'] != null ? data['id'] : 0; + this.id = data['id'] != null ? data['id'].toString() : ""; this.name = data['name'] != null ? data['name'] : ""; + this.role = data['role'] != null ? data['role'] : ""; } toJson() { - return {'id': id, 'name': name}; + return {'id': id, 'name': name, 'role': role}; } } diff --git a/lib/services/crm_services.dart b/lib/services/crm_services.dart index 5f5c484..18e6c9b 100644 --- a/lib/services/crm_services.dart +++ b/lib/services/crm_services.dart @@ -49,10 +49,16 @@ class CrmService { Future googleLogin(String idToken) async { try { + print("=== GOOGLE LOGIN DEBUG ==="); + print("Base URL: $baseUrl"); + print("Full URL: ${baseUrl}auth/google/"); + print("ID Token length: ${idToken.length}"); + print("=========================="); + Map headers = { 'Content-Type': 'application/json', }; - return await networkService.post(Uri.parse(baseUrl + 'auth/google'), + return await networkService.post(Uri.parse(baseUrl + 'auth/google/'), headers: headers, body: jsonEncode({'idToken': idToken})); } on SocketException { diff --git a/lib/ui/screens/authentication/companies_List.dart b/lib/ui/screens/authentication/companies_List.dart index 811df3d..942f898 100644 --- a/lib/ui/screens/authentication/companies_List.dart +++ b/lib/ui/screens/authentication/companies_List.dart @@ -85,8 +85,7 @@ class _CompaniesListState extends State { .getInstance(); preferences.setString( 'org', - (companies[index].id!) - .toString()); + companies[index].id!); authBloc.selectedOrganization = companies[index]; await fetchRequiredData(); @@ -118,17 +117,46 @@ class _CompaniesListState extends State { MainAxisAlignment .spaceBetween, children: [ - Container( - width: screenWidth * 0.7, - child: Text( - companies[index].name!, - style: TextStyle( - color: - bottomNavBarSelectedTextColor, - fontSize: - screenWidth / 24, - fontWeight: - FontWeight.bold), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + companies[index].name!, + style: TextStyle( + color: + bottomNavBarSelectedTextColor, + fontSize: + screenWidth / 24, + fontWeight: + FontWeight.bold), + ), + SizedBox(height: 4), + Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration( + color: companies[index].role == 'ADMIN' + ? Colors.blue.withOpacity(0.1) + : Colors.grey.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), + border: Border.all( + color: companies[index].role == 'ADMIN' + ? Colors.blue.withOpacity(0.3) + : Colors.grey.withOpacity(0.3) + ) + ), + child: Text( + companies[index].role ?? 'USER', + style: TextStyle( + color: companies[index].role == 'ADMIN' + ? Colors.blue[700] + : Colors.grey[700], + fontSize: screenWidth / 32, + fontWeight: FontWeight.w500 + ), + ), + ), + ], ), ), Container( diff --git a/lib/ui/screens/authentication/login.dart b/lib/ui/screens/authentication/login.dart index 3e92708..22ee87f 100644 --- a/lib/ui/screens/authentication/login.dart +++ b/lib/ui/screens/authentication/login.dart @@ -34,7 +34,6 @@ class _LoginState extends State { setState(() { _errorMessage = ''; }); - await authBloc.fetchCompanies(); await FirebaseAnalytics.instance.logEvent(name: "google_login"); Navigator.pushNamedAndRemoveUntil( context, '/companies_List', (route) => false); From 95a6bcae34cb6fef9a9e86e89c1589d1e8213897 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Wed, 30 Jul 2025 22:08:02 +0530 Subject: [PATCH 4/9] feat: Refactor Profile.fromJson to handle new Google login format and improve name parsing --- lib/model/profile.dart | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/lib/model/profile.dart b/lib/model/profile.dart index 3a484f9..05cd898 100644 --- a/lib/model/profile.dart +++ b/lib/model/profile.dart @@ -27,24 +27,47 @@ class Profile { this.isStaff}); Profile.fromJson(Map profile) { - this.id = profile['user_details']['id'] != null - ? profile['user_details']['id'] - : 0; + // Handle both old format (with user_details) and new format (flat structure) + if (profile['user_details'] != null) { + // Old format + this.id = profile['user_details']['id'] != null + ? profile['user_details']['id'] + : 0; + this.email = profile['user_details']['email'] != null + ? profile['user_details']['email'] + : ""; + this.firstName = profile['user_details']['first_name'] != null + ? profile['user_details']['first_name'] + : ""; + this.lastName = profile['user_details']['last_name'] != null + ? profile['user_details']['last_name'] + : ""; + this.profileUrl = profile['user_details']['profile_pic'] != null + ? profile['user_details']['profile_pic'] + : ""; + } else { + // New format (flat structure from Google login) + this.id = profile['id'] != null ? profile['id'].hashCode : 0; + this.email = profile['email'] != null ? profile['email'] : ""; + + // Parse name into firstName and lastName + if (profile['name'] != null) { + List nameParts = profile['name'].toString().split(' '); + this.firstName = nameParts.isNotEmpty ? nameParts.first : ""; + this.lastName = nameParts.length > 1 ? nameParts.skip(1).join(' ') : ""; + } else { + this.firstName = ""; + this.lastName = ""; + } + + this.profileUrl = profile['profileImage'] != null + ? profile['profileImage'] + : ""; + } + + // Common fields this.role = profile['role'] != null ? profile['role'] : ""; - this.profileUrl = profile['user_details']['profile_pic'] != null - ? profile['user_details']['profile_pic'] - : ""; - this.dateOfJoin = - profile['date_of_joining'] != null ? profile['date_of_joining'] : ""; - this.email = profile['user_details']['email'] != null - ? profile['user_details']['email'] - : ""; - this.firstName = profile['user_details']['first_name'] != null - ? profile['user_details']['first_name'] - : ""; - this.lastName = profile['user_details']['last_name'] != null - ? profile['user_details']['last_name'] - : ""; + this.dateOfJoin = profile['date_of_joining'] != null ? profile['date_of_joining'] : ""; this.hasMarketingAccess = profile['has_marketing_access'] != null ? profile['has_marketing_access'] : false; From 20df1ea63cc0c22ce6cc555c669be5ec76dc6456 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Wed, 30 Jul 2025 23:28:20 +0530 Subject: [PATCH 5/9] feat: Add organization selection screen and dashboard functionality - Implemented OrganizationSelectionScreen for users to select their organization. - Created DashboardController to manage dashboard state and data loading. - Developed ModernDashboardScreen to display dashboard content with responsive layouts. - Introduced DashboardState classes to handle different states of the dashboard. - Updated utils to remove unnecessary profile data fetching after login. - Enhanced error handling and loading states across dashboard components. --- CLAUDE.md | 24 + REFACTORING_PLAN.md | 174 +++++ lib/bloc/auth_bloc.dart | 21 +- lib/main.dart | 12 +- lib/services/crm_services.dart | 365 +++++---- lib/services/network_services.dart | 76 +- lib/ui/screens/authentication/login.dart | 2 + .../modern/authentication/login_screen.dart | 490 ++++++++++++ .../organization_selection_screen.dart | 716 ++++++++++++++++++ .../screens/modern/dashboard_controller.dart | 134 ++++ lib/ui/screens/modern/dashboard_screen.dart | 547 +++++++++++++ lib/ui/screens/modern/dashboard_state.dart | 52 ++ lib/utils/utils.dart | 3 +- 13 files changed, 2407 insertions(+), 209 deletions(-) create mode 100644 REFACTORING_PLAN.md create mode 100644 lib/ui/screens/modern/authentication/login_screen.dart create mode 100644 lib/ui/screens/modern/authentication/organization_selection_screen.dart create mode 100644 lib/ui/screens/modern/dashboard_controller.dart create mode 100644 lib/ui/screens/modern/dashboard_screen.dart create mode 100644 lib/ui/screens/modern/dashboard_state.dart diff --git a/CLAUDE.md b/CLAUDE.md index d119746..a54664e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -98,6 +98,30 @@ Future> getEntities() async { - **Background**: `#ECEEF4` (light gray) - **Custom Widgets**: Use existing widgets like `DashboardCountCard`, `RecentCardWidget` +## Refactoring Plan + +**IMPORTANT**: This project is undergoing incremental refactoring/modernization. Before enhancing any screen: + +1. **Check REFACTORING_PLAN.md** for the current status of the screen +2. **If modernizing a screen**: + - Create new version in `lib/ui/screens/modern/` directory + - Follow the modern patterns established in completed screens + - Update the progress status in REFACTORING_PLAN.md + - Keep legacy version as backup until migration is complete + +**Current Status**: 9.4% complete (3/32 screens modernized) +- ✅ Authentication: Login, Organization Selection +- ✅ Dashboard: Modern responsive dashboard +- 🔄 Pending: All CRM modules (Accounts, Contacts, Leads, etc.) + +**Modern Folder Structure**: +``` +lib/ui/screens/modern/ +├── authentication/ # Modern auth screens +├── dashboard_screen.dart +└── shared/ # Common components +``` + ## Configuration Notes - **Firebase**: Integrated for analytics (configuration in `android/app/google-services.json`) diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md new file mode 100644 index 0000000..df9c6ad --- /dev/null +++ b/REFACTORING_PLAN.md @@ -0,0 +1,174 @@ +# BottleCRM Mobile Refactoring Plan + +## Overview +This document tracks the incremental refactoring/modernization of BottleCRM Mobile screens and components. + +## Refactoring Strategy + +### Folder Structure +``` +lib/ui/screens/ +├── [original files] # Legacy screens in original locations +└── modern/ # Refactored screens + ├── authentication/ # Modern auth screens + ├── dashboard_screen.dart + └── shared/ # Common components +``` + +### Progress Tracking + +## 📱 Screens Status + +### ✅ Authentication Module +- [x] `login.dart` → `modern/authentication/login_screen.dart` - ✨ **MODERNIZED** (JWT token handling, improved UI) +- [x] `companies_List.dart` → `modern/authentication/organization_selection_screen.dart` - ✨ **ENHANCED** (Search functionality, gradient designs, staggered animations, improved responsive layouts) +- [ ] `register.dart` - 🔄 **PENDING** +- [ ] `forgot_password.dart` - 🔄 **PENDING** +- [ ] `change_password.dart` - 🔄 **PENDING** +- [ ] `profile.dart` - 🔄 **PENDING** + +### ✅ Dashboard Module +- [x] `dashboard.dart` → `modern/dashboard_screen.dart` - ✨ **MODERNIZED** (Responsive design, modern state management, enhanced UX) + +### 🔄 CRM Modules +#### Accounts +- [ ] `accounts_list.dart` - 🔄 **PENDING** +- [ ] `account_create.dart` - 🔄 **PENDING** +- [ ] `account_details.dart` - 🔄 **PENDING** + +#### Contacts +- [ ] `contacts_list.dart` - 🔄 **PENDING** +- [ ] `contact_create.dart` - 🔄 **PENDING** +- [ ] `contact_details.dart` - 🔄 **PENDING** + +#### Leads +- [ ] `leads_list.dart` - 🔄 **PENDING** +- [ ] `lead_create.dart` - 🔄 **PENDING** +- [ ] `lead_details.dart` - 🔄 **PENDING** + +#### Opportunities +- [ ] `opportunities_list.dart` - 🔄 **PENDING** +- [ ] `opportunitie_create.dart` - 🔄 **PENDING** +- [ ] `opportunitie_details.dart` - 🔄 **PENDING** + +#### Cases +- [ ] `cases_list.dart` - 🔄 **PENDING** +- [ ] `case_create.dart` - 🔄 **PENDING** +- [ ] `case_details.dart` - 🔄 **PENDING** + +#### Tasks +- [ ] `tasks_list.dart` - 🔄 **PENDING** +- [ ] `task_create.dart` - 🔄 **PENDING** +- [ ] `task_details.dart` - 🔄 **PENDING** + +#### Events +- [ ] `events_list.dart` - 🔄 **PENDING** +- [ ] `event_create.dart` - 🔄 **PENDING** +- [ ] `event_details.dart` - 🔄 **PENDING** + +#### Documents +- [ ] `documents_list.dart` - 🔄 **PENDING** +- [ ] `document_create.dart` - 🔄 **PENDING** +- [ ] `document_details.dart` - 🔄 **PENDING** + +#### Teams +- [ ] `teams_list.dart` - 🔄 **PENDING** +- [ ] `team_create.dart` - 🔄 **PENDING** +- [ ] `team_details.dart` - 🔄 **PENDING** + +#### Users +- [ ] `users_list.dart` - 🔄 **PENDING** +- [ ] `user_create.dart` - 🔄 **PENDING** +- [ ] `user_details.dart` - 🔄 **PENDING** + +#### Invoices +- [ ] `invoices_list.dart` - 🔄 **PENDING** +- [ ] `invoice_create.dart` - 🔄 **PENDING** +- [ ] `invoice_details.dart` - 🔄 **PENDING** + +#### Settings +- [ ] `settings.dart` - 🔄 **PENDING** +- [ ] `settings_details.dart` - 🔄 **PENDING** +- [ ] `settings_userDetails.dart` - 🔄 **PENDING** + +## 🎯 Modernization Goals + +### Technical Improvements +- [ ] **State Management**: Migrate from custom BLoC to modern state management (Riverpod/Bloc) +- [ ] **UI Framework**: Adopt modern Flutter widgets and Material 3 +- [ ] **Architecture**: Implement clean architecture patterns +- [ ] **Error Handling**: Standardize error handling across screens +- [ ] **Loading States**: Consistent loading and empty states +- [ ] **Responsive Design**: Enhanced responsive layouts +- [ ] **Accessibility**: Add accessibility features +- [ ] **Testing**: Add unit and widget tests + +### UI/UX Improvements +- [ ] **Design System**: Create consistent design tokens +- [ ] **Dark Mode**: Implement system-wide dark mode +- [ ] **Animations**: Add smooth transitions and micro-animations +- [ ] **Performance**: Optimize rendering and memory usage +- [ ] **Offline Support**: Add offline capabilities where applicable + +## 🔄 Routing Updates + +### Modern Routes (Active) +- `/login` → `LoginScreen()` (modern login) +- `/organization_selection` → `OrganizationSelectionScreen()` (modern org selection) +- `/dashboard` → `ModernDashboardScreen()` (modern dashboard) + +### Legacy Routes (Backup) +- `/login_legacy` → `Login()` (original login) +- `/companies_List` → `CompaniesList()` (original companies list) +- `/dashboard_legacy` → `Dashboard()` (original dashboard) + +## 📋 Migration Steps + +### Phase 1: Authentication & Core (✨ COMPLETED) +1. ✅ Login screen with JWT handling → **MOVED** to `modern/authentication/` +2. ✅ Organization selection with role display → **MOVED** to `modern/authentication/` +3. ✅ Profile model updates + +### Phase 2: Dashboard & Navigation (✅ COMPLETED) +1. ✅ Modern dashboard with cards and analytics → **MOVED** to `modern/dashboard_screen.dart` +2. 🔄 Bottom navigation improvements +3. 🔄 Side drawer/app bar enhancements + +### Phase 3: CRM Modules (📅 PLANNED) +1. 📅 Accounts module modernization +2. 📅 Contacts module modernization +3. 📅 Leads module modernization +4. 📅 Continue with remaining modules... + +## 🔧 Development Guidelines + +### File Naming Convention +- Legacy files: Keep original names in `legacy/` folder +- Modern files: Use descriptive names with `_screen.dart` suffix +- Shared components: Use `component_name.dart` in `shared/` + +### Code Standards +- Use null safety throughout +- Implement proper error handling +- Add documentation comments +- Follow Flutter best practices +- Use consistent coding style + +### Testing Strategy +- Unit tests for business logic +- Widget tests for UI components +- Integration tests for critical flows + +## 📊 Progress Metrics + +**Overall Progress**: 9.4% (3/32 screens completed) + +### By Module: +- Authentication: 33% (2/6) +- Dashboard: 100% (1/1) ✅ +- CRM Modules: 0% (0/25) + +--- + +*Last Updated: 2025-01-30* +*Next Review: After completing Phase 2* \ No newline at end of file diff --git a/lib/bloc/auth_bloc.dart b/lib/bloc/auth_bloc.dart index 095caf7..fa3c206 100644 --- a/lib/bloc/auth_bloc.dart +++ b/lib/bloc/auth_bloc.dart @@ -88,7 +88,7 @@ class AuthBloc { print("============================"); if (response.statusCode == 200 && res['success'] == true && res['JWTtoken'] != null) { - _authToken = "JWT " + res['JWTtoken']; + _authToken = "Bearer " + res['JWTtoken']; preferences.setString("authToken", _authToken!); // Store user profile data if available @@ -191,6 +191,25 @@ class AuthBloc { } } + + Future clearAllStoredData() async { + final SharedPreferences preferences = await SharedPreferences.getInstance(); + + // Clear all stored preferences + await preferences.remove('authToken'); + await preferences.remove('org'); + await preferences.remove('userProfile'); + await preferences.remove('selectedOrganization'); + + // Clear bloc state variables + _authToken = null; + _userProfile = null; + _companies.clear(); + _selectedOrganization = null; + _subDomainName = null; + + print("All stored data cleared successfully"); + } } final authBloc = AuthBloc(); diff --git a/lib/main.dart b/lib/main.dart index 19809ca..13b7a80 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,8 +3,10 @@ import 'package:bottle_crm/ui/screens/accounts/account_create.dart'; import 'package:bottle_crm/ui/screens/accounts/account_details.dart'; import 'package:bottle_crm/ui/screens/authentication/change_password.dart'; import 'package:bottle_crm/ui/screens/authentication/companies_List.dart'; +import 'package:bottle_crm/ui/screens/modern/authentication/organization_selection_screen.dart'; import 'package:bottle_crm/ui/screens/authentication/forgot_password.dart'; import 'package:bottle_crm/ui/screens/authentication/login.dart'; +import 'package:bottle_crm/ui/screens/modern/authentication/login_screen.dart'; import 'package:bottle_crm/ui/screens/authentication/profile.dart'; import 'package:bottle_crm/ui/screens/authentication/register.dart'; import 'package:bottle_crm/ui/screens/cases/case_create.dart'; @@ -14,6 +16,7 @@ import 'package:bottle_crm/ui/screens/contacts/contact_create.dart'; import 'package:bottle_crm/ui/screens/contacts/contact_details.dart'; import 'package:bottle_crm/ui/screens/contacts/contacts_list.dart'; import 'package:bottle_crm/ui/screens/dashboard/dashboard.dart'; +import 'package:bottle_crm/ui/screens/modern/dashboard_screen.dart'; import 'package:bottle_crm/ui/screens/documents/documents_list.dart'; import 'package:bottle_crm/ui/screens/events/event_create.dart'; import 'package:bottle_crm/ui/screens/events/event_details.dart'; @@ -82,12 +85,14 @@ class MyApp extends StatelessWidget { ); }, routes: { - '/login': (BuildContext context) => Login(), + '/login': (BuildContext context) => LoginScreen(), // Modern login + '/login_legacy': (BuildContext context) => Login(), // Legacy login '/register': (BuildContext context) => Register(), '/forgot_password': (BuildContext context) => ForgotPassword(), '/change_password': (BuildContext context) => ChangePassword(), '/profile': (BuildContext context) => Profile(), - '/dashboard': (BuildContext context) => Dashboard(), + '/dashboard': (BuildContext context) => ModernDashboardScreen(), // Modern dashboard + '/dashboard_legacy': (BuildContext context) => Dashboard(), // Legacy dashboard '/more_options': (BuildContext context) => MoreOptions(), '/leads_list': (BuildContext context) => LeadsList(), '/leads_create': (BuildContext context) => CreateLead(), @@ -119,7 +124,8 @@ class MyApp extends StatelessWidget { '/users_list': (BuildContext context) => UsersList(), '/user_create': (BuildContext context) => CreateUser(), '/user_details': (BuildContext context) => UserDetails(), - '/companies_List': (BuildContext context) => CompaniesList(), + '/organization_selection': (BuildContext context) => OrganizationSelectionScreen(), // Modern org selection + '/companies_List': (BuildContext context) => CompaniesList(), // Legacy companies list '/settings_List': (BuildContext context) => SettingsList(), '/settings_details': (BuildContext context) => SettingsDeails(), '/settings_userDetails': (BuildContext context) => SettingsUserDetails(), diff --git a/lib/services/crm_services.dart b/lib/services/crm_services.dart index 18e6c9b..86284b9 100644 --- a/lib/services/crm_services.dart +++ b/lib/services/crm_services.dart @@ -6,7 +6,6 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:http/http.dart'; import 'package:http/http.dart' as http; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:bottle_crm/ui/screens/http_excepion.dart'; import 'package:bottle_crm/config/api_config.dart'; @@ -15,24 +14,14 @@ import 'network_services.dart'; class CrmService { NetworkService networkService = NetworkService(); String baseUrl = ApiConfig.getApiUrl(); - Map _headers = {}; // Method to set custom API URL void setBaseUrl(String url) { baseUrl = url.endsWith('/') ? url : '$url/'; } - updateHeaders() async { - final SharedPreferences preferences = await SharedPreferences.getInstance(); - _headers['Authorization'] = preferences.getString('authToken'); - if (preferences.getString('org') != null) { - _headers['org'] = preferences.getString('org'); - } - } - - getFormatedHeaders(headers) { - return new Map.from(headers); - } + // Header handling now centralized in NetworkService + // These methods are deprecated and will be removed Future userRegister(data) async { try { @@ -94,9 +83,7 @@ class CrmService { Future getUserProfile() async { try { - await updateHeaders(); - return await networkService.get(Uri.parse(baseUrl + 'profile/'), - headers: await getFormatedHeaders(_headers)); + return await networkService.get(Uri.parse(baseUrl + 'profile/')); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -106,10 +93,8 @@ class CrmService { Future changePassword(data) async { try { - await updateHeaders(); return await networkService.post( Uri.parse(baseUrl + 'profile/change-password/'), - headers: getFormatedHeaders(_headers), body: data); } on SocketException { throw HttpException("Network Error, check your internet"); @@ -120,10 +105,8 @@ class CrmService { Future getCompanies() async { try { - await updateHeaders(); return await networkService.get( - Uri.parse(baseUrl + 'auth/companies-list/'), - headers: await getFormatedHeaders(_headers)); + Uri.parse(baseUrl + 'auth/companies-list/')); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -133,9 +116,7 @@ class CrmService { Future getDashboardDetails() async { try { - await updateHeaders(); - return await networkService.get(Uri.parse(baseUrl + 'dashboard/'), - headers: await getFormatedHeaders(_headers)); + return await networkService.get(Uri.parse(baseUrl + 'dashboard/')); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -145,12 +126,12 @@ class CrmService { ///////////////////// ACCONUTS-SERVICES //////////////////////////// Future getAccounts({queryParams, offset}) async { - await updateHeaders(); + var url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'accounts/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -162,14 +143,14 @@ class CrmService { } } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deleteAccount(id) async { try { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'accounts/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -180,9 +161,9 @@ class CrmService { Future createAccount(data, File file) async { try { if (file.path == "") { - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'accounts/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } else { var uri = Uri.parse( baseUrl + 'accounts/', @@ -191,10 +172,10 @@ class CrmService { 'POST', uri, ) - ..headers.addAll(getFormatedHeaders(_headers)) ..fields.addAll(Map.from(data)) ..files.add( await http.MultipartFile.fromPath('document_file', 'assets/images/sentry_logo.png')); + await networkService.addAuthHeadersToMultipartRequest(request); var response = await request.send(); return await http.Response.fromStream(response); } @@ -207,9 +188,9 @@ class CrmService { Future editAccount(data, id) async { try { - await updateHeaders(); + return await networkService.put(Uri.parse(baseUrl + 'accounts/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -218,20 +199,20 @@ class CrmService { } Future getToEditAccount(id) async { - await updateHeaders(); - return await networkService.get(baseUrl + 'accounts/$id/', - headers: getFormatedHeaders(_headers)); + + return await networkService.get(Uri.parse(baseUrl + 'accounts/$id/'), + ); } ///////////////////// CONTACTS-SERVICES /////////////////////////////// Future getContacts({queryParams, offset}) async { - await updateHeaders(); + var url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'contacts/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -243,15 +224,15 @@ class CrmService { } } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future createContact(data, File file) async { try { if (file.path == "") { - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'contacts/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } else { var uri = Uri.parse( baseUrl + 'contacts/', @@ -259,11 +240,11 @@ class CrmService { var request = http.MultipartRequest( 'POST', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll(Map.from(data)) - ..files.add( - await http.MultipartFile.fromPath('document_file', file.path)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll(Map.from(data)); + request.files.add( + await http.MultipartFile.fromPath('document_file', file.path)); var response = await request.send(); return await http.Response.fromStream(response); } @@ -276,9 +257,9 @@ class CrmService { Future editContact(data, id) async { try { - await updateHeaders(); + return await networkService.put(Uri.parse(baseUrl + 'contacts/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -288,9 +269,9 @@ class CrmService { Future deleteContact(id) async { try { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'contacts/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -301,12 +282,12 @@ class CrmService { ///////////////////// LEADS-SERVICES /////////////////////////////// Future getLeads({queryParams, offset}) async { - await updateHeaders(); + var url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = Uri( - queryParameters: getFormatedHeaders(queryParams), + queryParameters: queryParams, ).query; url = Uri.parse(baseUrl + 'leads/' + '?' + queryString); if (offset != null && offset != "") { @@ -319,34 +300,34 @@ class CrmService { } } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future getLeadToUpdate(leadId) async { - await updateHeaders(); - return await networkService.get(baseUrl + 'leads/$leadId/', - headers: getFormatedHeaders(_headers)); + + return await networkService.get(Uri.parse(baseUrl + 'leads/$leadId/'), + ); } Future createLead(data, File file) async { try { if (file.path == "") { - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'leads/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } else { - await updateHeaders(); + var uri = Uri.parse( baseUrl + 'leads/', ); var request = http.MultipartRequest( 'POST', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll(Map.from(data)) - ..files.add( - await http.MultipartFile.fromPath('document_file', file.path)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll(Map.from(data)); + request.files.add( + await http.MultipartFile.fromPath('document_file', file.path)); var response = await request.send(); return await http.Response.fromStream(response); } @@ -359,9 +340,9 @@ class CrmService { Future editLead(data, id) async { try { - await updateHeaders(); + return await networkService.put(Uri.parse(baseUrl + 'leads/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -371,9 +352,9 @@ class CrmService { Future deleteLead(id) async { try { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'leads/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -384,24 +365,24 @@ class CrmService { ///////////////////// USERS-SERVICES /////////////////////////////// Future getUsers({Map? queryParams}) async { - await updateHeaders(); + Uri url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'users/' + '?' + queryString); } else { url = Uri.parse(baseUrl + 'users/'); } - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deleteUser(id) async { try { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'users/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -412,22 +393,22 @@ class CrmService { Future createUser(user, File file) async { try { if (file.path == "") { - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'users/'), - headers: getFormatedHeaders(_headers), body: user); + body: user); } else { - await updateHeaders(); + var uri = Uri.parse( - baseUrl + 'users//', + baseUrl + 'users/', ); var request = http.MultipartRequest( 'POST', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll(Map.from(user)) - ..files.add( - await http.MultipartFile.fromPath('document_file', file.path)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll(Map.from(user)); + request.files.add( + await http.MultipartFile.fromPath('document_file', file.path)); var response = await request.send(); return await http.Response.fromStream(response); } @@ -440,9 +421,9 @@ class CrmService { Future editUser(user, id) async { try { - await updateHeaders(); + return await networkService.put(Uri.parse(baseUrl + 'users/$id/'), - headers: getFormatedHeaders(_headers), body: user); + body: user); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -454,25 +435,25 @@ class CrmService { ///////////////////// Events-SERVICES /////////////////////////////// Future getEvents({Map? queryParams}) async { - await updateHeaders(); + Uri url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'events/' + '?' + queryString); } else { url = Uri.parse(baseUrl + 'events/'); } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deleteEvent(id) async { try { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'events/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -482,9 +463,9 @@ class CrmService { Future createEvent(user) async { try { - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'events/'), - headers: getFormatedHeaders(_headers), body: user); + body: user); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -494,9 +475,9 @@ class CrmService { Future editEvent(user, id) async { try { - await updateHeaders(); + return await networkService.put(Uri.parse(baseUrl + 'events/$id/'), - headers: getFormatedHeaders(_headers), body: user); + body: user); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -507,18 +488,18 @@ class CrmService { ///////////////////// DOCUMENTS-SERVICES /////////////////////////////// Future getDocuments({queryParams}) async { - await updateHeaders(); + String url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = Uri( - queryParameters: getFormatedHeaders(queryParams), + queryParameters: queryParams, ).query; url = baseUrl + 'documents/' + '?' + queryString; } else { url = baseUrl + 'documents/'; } - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } getFileSizes(files) { @@ -538,22 +519,22 @@ class CrmService { Future createDocument(document, PlatformFile file) async { try { - await updateHeaders(); + var uri = Uri.parse( baseUrl + 'documents/', ); var request = http.MultipartRequest( 'POST', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll({ - 'title': document['title'], - 'teams': document['teams'], - 'shared_to': document['shared_to'] - }) - ..files.add( - await http.MultipartFile.fromPath('document_file', file.path!)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll({ + 'title': document['title'], + 'teams': document['teams'], + 'shared_to': document['shared_to'] + }); + request.files.add( + await http.MultipartFile.fromPath('document_file', file.path!)); final response = await request.send(); return await response.stream.bytesToString(); } on SocketException { @@ -564,31 +545,31 @@ class CrmService { } Future editDocument(document, PlatformFile file, id) async { - await updateHeaders(); + var uri = Uri.parse( baseUrl + 'documents/$id/', ); var request = http.MultipartRequest( 'PUT', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll({ - 'title': document['title'], - 'teams': document['teams'], - 'shared_to': document['shared_to'], - 'status': document['status'] - }) - ..files - .add(await http.MultipartFile.fromPath('document_file', file.path!)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll({ + 'title': document['title'], + 'teams': document['teams'], + 'shared_to': document['shared_to'], + 'status': document['status'] + }); + request.files + .add(await http.MultipartFile.fromPath('document_file', file.path!)); return await request.send(); } Future deleteDocument(id) async { try { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'documents/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -599,7 +580,7 @@ class CrmService { ///////////////////// TEAMS-SERVICES /////////////////////////////// Future getTeams({queryParams, offset}) async { - await updateHeaders(); + Uri url; if (queryParams != null) { queryParams.removeWhere((key, value) => value.runtimeType != String); @@ -607,7 +588,7 @@ class CrmService { queryParams.removeWhere((key, value) => value == ""); queryParams.removeWhere((key, value) => value == null); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'teams/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -619,7 +600,7 @@ class CrmService { } } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future createTeam(data) async { @@ -627,9 +608,9 @@ class CrmService { data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'teams/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -638,32 +619,32 @@ class CrmService { } Future deleteTeam(id) async { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'teams/$id/'), - headers: getFormatedHeaders(_headers)); + ); } Future editTeam( data, id, ) async { - await updateHeaders(); + data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); return await networkService.put(Uri.parse(baseUrl + 'teams/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } ///////////////////// OPPORTUNITIES-SERVICES //////////////////////////// Future getOpportunities({queryParams, offset}) async { - await updateHeaders(); + Uri url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'opportunities/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -675,15 +656,15 @@ class CrmService { } } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deletefromModule(moduleName, id) async { try { - await updateHeaders(); + return await networkService.delete( Uri.parse(baseUrl + '$moduleName/$id/'), - headers: getFormatedHeaders(_headers)); + ); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -693,7 +674,7 @@ class CrmService { // Future createOpportunity(opportunity, [PlatformFile file]) async { // file = null; - // await updateHeaders(); + // // var uri = Uri.parse( // baseUrl + 'opportunities/', // ); @@ -701,7 +682,7 @@ class CrmService { // 'POST', // uri, // ) - // ..headers.addAll(getFormatedHeaders(_headers)) + // // Headers automatically added by NetworkService // ..fields.addAll({ // 'name': opportunity['name'], // 'account': opportunity['account'], @@ -731,22 +712,22 @@ class CrmService { data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'opportunities/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } else { - await updateHeaders(); + var uri = Uri.parse( baseUrl + 'opportunities/', ); var request = http.MultipartRequest( 'POST', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll(Map.from(data)) - ..files.add( - await http.MultipartFile.fromPath('document_file', file.path)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll(Map.from(data)); + request.files.add( + await http.MultipartFile.fromPath('document_file', file.path)); var response = await request.send(); return await http.Response.fromStream(response); } @@ -759,12 +740,12 @@ class CrmService { Future editOpportunity(data, id, [PlatformFile? file]) async { try { - await updateHeaders(); + data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); return await networkService.put(Uri.parse(baseUrl + 'opportunities/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -773,7 +754,7 @@ class CrmService { } // Future editOpportunity(opportunity, id, [PlatformFile file]) async { - // await updateHeaders(); + // // var uri = Uri.parse( // baseUrl + 'opportunities`/$id/', // ); @@ -782,7 +763,7 @@ class CrmService { // 'PUT', // uri, // ) - // ..headers.addAll(getFormatedHeaders(_headers)) + // // Headers automatically added by NetworkService // ..fields.addAll({ // 'name': opportunity['name'], // 'account': opportunity['account'], @@ -806,11 +787,11 @@ class CrmService { ///////////////////// TASKS-SERVICES /////////////////////////////// Future getTasks({queryParams, offset}) async { - await updateHeaders(); + Uri? url; if (queryParams != null) { String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'tasks/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -822,17 +803,17 @@ class CrmService { url = Uri.parse(baseUrl + 'tasks/'); } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future createTask(data) async { try { - await updateHeaders(); + data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); return await networkService.post(Uri.parse(baseUrl + 'tasks/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -841,29 +822,29 @@ class CrmService { } Future editTask(data, id) async { - await updateHeaders(); + data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); return await networkService.put(Uri.parse(baseUrl + 'tasks/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } Future deleteTask(id) async { - await updateHeaders(); + return await networkService.delete(Uri.parse(baseUrl + 'tasks/$id/'), - headers: getFormatedHeaders(_headers)); + ); } ///////////////////// SETTINGS-SERVICES /////////////////////////////// Future getApiSettings({queryParams, offset}) async { - await updateHeaders(); + Uri? url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'api-settings/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -875,78 +856,78 @@ class CrmService { url = Uri.parse(baseUrl + 'api-settings/'); } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } /// CONTACTS Future getSettingsContacts({queryParams}) async { - await updateHeaders(); + String url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = baseUrl + 'settings/contacts/' + '?' + queryString; } else { url = baseUrl + 'settings/contacts/'; } - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deleteSettingsContacts(id) async { - await updateHeaders(); + return await networkService.delete( Uri.parse(baseUrl + 'settings/contacts/$id/'), - headers: getFormatedHeaders(_headers)); + ); } /// BLOCKED DOMAINS Future getBlockedDomains({queryParams}) async { - await updateHeaders(); + String url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = baseUrl + 'settings/block-domains/' + '?' + queryString; } else { url = baseUrl + 'settings/block-domains/'; } - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deleteBlockedDomains(id) async { - await updateHeaders(); + return await networkService.delete( Uri.parse(baseUrl + 'settings/block-domains/$id/'), - headers: getFormatedHeaders(_headers)); + ); } /// BLOCKED EMAILS Future getBlockedEmails({queryParams}) async { - await updateHeaders(); + String url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = baseUrl + 'settings/block-emails/' + '?' + queryString; } else { url = baseUrl + 'settings/block-emails/'; } - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future deleteBlockedEmails(id) async { - await updateHeaders(); + return await networkService.delete( Uri.parse(baseUrl + 'settings/block-emails/$id/'), - headers: getFormatedHeaders(_headers)); + ); } Future createSetting(data) async { try { - await updateHeaders(); + data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); @@ -959,7 +940,7 @@ class CrmService { // _url = '/settings/block-emails'; // } return await networkService.post(Uri.parse(baseUrl + '$_url/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { @@ -968,7 +949,7 @@ class CrmService { } Future editSetting(data, id) async { - await updateHeaders(); + data.removeWhere((key, value) => value == "[]"); data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); @@ -981,13 +962,13 @@ class CrmService { // _url = '/settings/block-emails'; // } return await networkService.put(Uri.parse(baseUrl + '$_url/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } ///////////////////// CASES-SERVICES /////////////////////////////// Future getCases({queryParams, offset}) async { - await updateHeaders(); + Uri url; if (queryParams != null) { queryParams.removeWhere((key, value) => value == ""); @@ -995,7 +976,7 @@ class CrmService { queryParams.removeWhere((key, value) => value == []); String queryString = - Uri(queryParameters: getFormatedHeaders(queryParams)).query; + Uri(queryParameters: Map.from(queryParams)).query; url = Uri.parse(baseUrl + 'cases/' + '?' + queryString); if (offset != null && offset != "") { url = Uri.parse(url.toString() + '&offset=$offset'); @@ -1007,7 +988,7 @@ class CrmService { } } print(url); - return await networkService.get(url, headers: getFormatedHeaders(_headers)); + return await networkService.get(url); } Future createCase(data, File file) async { @@ -1016,22 +997,22 @@ class CrmService { // data.removeWhere((key, value) => value == "[]"); // data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); - await updateHeaders(); + return await networkService.post(Uri.parse(baseUrl + 'cases/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } else { - await updateHeaders(); + var uri = Uri.parse( baseUrl + 'leads/', ); var request = http.MultipartRequest( 'POST', uri, - ) - ..headers.addAll(getFormatedHeaders(_headers)) - ..fields.addAll(Map.from(data)) - ..files.add( - await http.MultipartFile.fromPath('document_file', file.path)); + ); + await networkService.addAuthHeadersToMultipartRequest(request); + request.fields.addAll(Map.from(data)); + request.files.add( + await http.MultipartFile.fromPath('document_file', file.path)); var response = await request.send(); return await http.Response.fromStream(response); } @@ -1044,12 +1025,12 @@ class CrmService { Future editCase(data, id, [PlatformFile? file]) async { try { - await updateHeaders(); + // data.removeWhere((key, value) => value == "[]"); // data.removeWhere((key, value) => value == ""); data.removeWhere((key, value) => value == null); return await networkService.put(Uri.parse(baseUrl + 'cases/$id/'), - headers: getFormatedHeaders(_headers), body: data); + body: data); } on SocketException { throw HttpException("Network Error, check your internet"); } catch (e) { diff --git a/lib/services/network_services.dart b/lib/services/network_services.dart index 2301ca4..8ce2841 100644 --- a/lib/services/network_services.dart +++ b/lib/services/network_services.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:bottle_crm/ui/screens/http_excepion.dart'; class NetworkService { @@ -11,6 +12,47 @@ class NetworkService { NetworkService.internal(); + // Centralized method to get headers with JWT token and organization + Future> _getAuthenticatedHeaders([Map? additionalHeaders]) async { + final SharedPreferences preferences = await SharedPreferences.getInstance(); + + Map headers = { + 'Content-Type': 'application/json', + }; + + // Add Bearer token if available + final String? authToken = preferences.getString('authToken'); + if (authToken != null) { + // Convert from "JWT " format to "Bearer " format + String bearerToken = authToken; + if (authToken.startsWith('JWT ')) { + bearerToken = authToken.replaceFirst('JWT ', 'Bearer '); + } else if (!authToken.startsWith('Bearer ')) { + bearerToken = 'Bearer $authToken'; + } + headers['Authorization'] = bearerToken; + } + + // Add organization header if available + final String? org = preferences.getString('org'); + if (org != null) { + headers['X-Organization-ID'] = org; + } + + // Merge with any additional headers provided + if (additionalHeaders != null) { + headers.addAll(additionalHeaders); + } + + return headers; + } + + // Helper method to add authenticated headers to MultipartRequest + Future addAuthHeadersToMultipartRequest(http.MultipartRequest request) async { + final headers = await _getAuthenticatedHeaders(); + request.headers.addAll(headers); + } + // Helper method to print long strings in chunks void _printLongString(String title, String content) { const int chunkSize = 800; @@ -27,13 +69,16 @@ class NetworkService { Future get(var url, {Map? headers}) async { try { + // Get authenticated headers (merge with provided headers) + Map finalHeaders = await _getAuthenticatedHeaders(headers); + // Log request details print("=== GET REQUEST ==="); print("URL: $url"); - print("Headers: $headers"); + print("Headers: $finalHeaders"); print("=================="); - return client.get(url, headers: headers).then((http.Response response) { + return client.get(url, headers: finalHeaders).then((http.Response response) { // Log response details print("=== GET RESPONSE ==="); print("Status Code: ${response.statusCode}"); @@ -55,17 +100,20 @@ class NetworkService { } Future post(Uri url, - {Map? headers, body, encoding}) { + {Map? headers, body, encoding}) async { try { + // Get authenticated headers (merge with provided headers) + Map finalHeaders = await _getAuthenticatedHeaders(headers); + // Log request details print("=== POST REQUEST ==="); print("URL: $url"); - print("Headers: $headers"); + print("Headers: $finalHeaders"); _printLongString("Body:", body?.toString() ?? "null"); print("=================="); return client - .post(url, headers: headers, body: body, encoding: encoding) + .post(url, headers: finalHeaders, body: body, encoding: encoding) .then((http.Response response) { // Log response details print("=== POST RESPONSE ==="); @@ -91,17 +139,20 @@ class NetworkService { } Future put(Uri url, - {Map? headers, body, encoding}) { + {Map? headers, body, encoding}) async { try { + // Get authenticated headers (merge with provided headers) + Map finalHeaders = await _getAuthenticatedHeaders(headers); + // Log request details print("=== PUT REQUEST ==="); print("URL: $url"); - print("Headers: $headers"); + print("Headers: $finalHeaders"); _printLongString("Body:", body?.toString() ?? "null"); print("=================="); return client - .put(url, headers: headers, body: body, encoding: encoding) + .put(url, headers: finalHeaders, body: body, encoding: encoding) .then((http.Response response) { // Log response details print("=== PUT RESPONSE ==="); @@ -117,16 +168,19 @@ class NetworkService { } } - Future delete(Uri url, {Map? headers}) { + Future delete(Uri url, {Map? headers}) async { try { + // Get authenticated headers (merge with provided headers) + Map finalHeaders = await _getAuthenticatedHeaders(headers); + // Log request details print("=== DELETE REQUEST ==="); print("URL: $url"); - print("Headers: $headers"); + print("Headers: $finalHeaders"); print("====================="); return client - .delete(url, headers: headers) + .delete(url, headers: finalHeaders) .then((http.Response response) { // Log response details print("=== DELETE RESPONSE ==="); diff --git a/lib/ui/screens/authentication/login.dart b/lib/ui/screens/authentication/login.dart index 22ee87f..2d07451 100644 --- a/lib/ui/screens/authentication/login.dart +++ b/lib/ui/screens/authentication/login.dart @@ -20,6 +20,8 @@ class _LoginState extends State { @override void initState() { super.initState(); + // Clear all stored data when login page opens + authBloc.clearAllStoredData(); } diff --git a/lib/ui/screens/modern/authentication/login_screen.dart b/lib/ui/screens/modern/authentication/login_screen.dart new file mode 100644 index 0000000..ff1bfd7 --- /dev/null +++ b/lib/ui/screens/modern/authentication/login_screen.dart @@ -0,0 +1,490 @@ +import 'package:bottle_crm/responsive.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:flutter/material.dart'; + +import 'package:flutter_svg/svg.dart'; + +import 'package:bottle_crm/bloc/auth_bloc.dart'; +import 'package:bottle_crm/utils/utils.dart'; + +class LoginScreen extends StatefulWidget { + const LoginScreen({Key? key}) : super(key: key); + + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + bool _isLoading = false; + String _errorMessage = ''; + + @override + void initState() { + super.initState(); + // Clear all stored data when login page opens + authBloc.clearAllStoredData(); + } + + + _googleLogin() async { + setState(() { + _isLoading = true; + }); + + try { + Map result = await authBloc.googleLogin(); + if (result['error'] == false) { + setState(() { + _errorMessage = ''; + }); + await FirebaseAnalytics.instance.logEvent(name: "google_login"); + Navigator.pushNamedAndRemoveUntil( + context, '/organization_selection', (route) => false); + } else { + setState(() { + _errorMessage = result['message'] ?? 'Google login failed'; + }); + } + } catch (e) { + setState(() { + _errorMessage = 'Google login failed. Please try again.'; + }); + } + + setState(() { + _isLoading = false; + }); + } + + + Widget loginWidget() { + return Responsive( + mobile: buildMobileScreen(), + tablet: buildTabletScreen(), + desktop: Container()); + } + + buildMobileScreen() { + return SingleChildScrollView( + child: Container( + height: screenHeight, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Theme.of(context).primaryColor, + Theme.of(context).primaryColor.withOpacity(0.8), + ], + ), + ), + child: Column( + children: [ + SizedBox(height: screenHeight * 0.08), + // Logo and Branding Section + Container( + padding: EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + SvgPicture.asset( + 'assets/images/logo.svg', + width: screenWidth * 0.4, + color: Colors.white, + ), + SizedBox(height: 20), + Text( + 'BottleCRM', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 10, + fontWeight: FontWeight.bold, + letterSpacing: 1.2, + ), + ), + SizedBox(height: 10), + Text( + 'Free CRM for startups and enterprises', + style: TextStyle( + color: Colors.white.withOpacity(0.9), + fontSize: screenWidth / 25, + fontWeight: FontWeight.w400, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + SizedBox(height: screenHeight * 0.08), + // Login Card + Expanded( + child: Container( + width: screenWidth, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), + topRight: Radius.circular(30), + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 20, + offset: Offset(0, -5), + ), + ], + ), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Welcome Back!', + style: TextStyle( + color: Colors.black87, + fontSize: screenWidth / 12, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 10), + Text( + 'Sign in to continue managing your business', + style: TextStyle( + color: Colors.grey[600], + fontSize: screenWidth / 26, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: screenHeight * 0.05), + _errorMessage != '' + ? Container( + margin: EdgeInsets.only(bottom: 20.0), + padding: EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.red.withOpacity(0.3)), + ), + child: Row( + children: [ + Icon(Icons.error_outline, color: Colors.red, size: 20), + SizedBox(width: 8), + Expanded( + child: Text( + _errorMessage, + style: TextStyle( + color: Colors.red[700], + fontSize: screenWidth / 30, + ), + ), + ), + ], + ), + ) + : SizedBox(), + !_isLoading + ? Container( + width: screenWidth, + height: 56, + child: ElevatedButton( + onPressed: _googleLogin, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black87, + elevation: 2, + shadowColor: Colors.black26, + side: BorderSide(color: Colors.grey[300]!, width: 1), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/google-icon.png', + width: 24, + height: 24, + ), + SizedBox(width: 16), + Text( + 'Continue with Google', + style: TextStyle( + fontSize: screenWidth / 22, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ) + : Container( + height: 56, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + Theme.of(context).primaryColor), + ), + ), + ), + SizedBox(height: screenHeight * 0.04), + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.withOpacity(0.05), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.withOpacity(0.2)), + ), + child: Row( + children: [ + Icon(Icons.info_outline, color: Colors.blue, size: 20), + SizedBox(width: 8), + Expanded( + child: Text( + 'Secure sign-in powered by Google OAuth 2.0', + style: TextStyle( + color: Colors.blue[700], + fontSize: screenWidth / 32, + ), + ), + ), + ], + ), + ), + SizedBox( + height: screenHeight * 0.05, + ), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + buildTabletScreen() { + return Container( + height: screenHeight, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Theme.of(context).primaryColor, + Theme.of(context).primaryColor, + ], + ), + ), + child: Row( + children: [ + // Left side - Branding + Expanded( + flex: 1, + child: Container( + padding: EdgeInsets.all(40), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset( + 'assets/images/logo.svg', + width: screenWidth * 0.15, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), + SizedBox(height: 30), + Text( + 'BottleCRM', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 20, + fontWeight: FontWeight.bold, + letterSpacing: 1.2, + ), + ), + SizedBox(height: 15), + Text( + 'Free CRM for startups and enterprises', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 50, + fontWeight: FontWeight.w400, + height: 1.5, + ), + ), + SizedBox(height: 30), + Text( + 'Manage your customers, leads, and opportunities all in one place.', + style: TextStyle( + color: Colors.white, + fontSize: screenWidth / 60, + height: 1.6, + ), + ), + ], + ), + ), + ), + // Right side - Login Form + Expanded( + flex: 1, + child: Container( + margin: EdgeInsets.all(40), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 20, + offset: Offset(0, 10), + ), + ], + ), + child: Container( + padding: EdgeInsets.all(40), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Welcome Back!', + style: TextStyle( + color: Colors.black87, + fontSize: screenWidth / 25, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 10), + Text( + 'Sign in to continue managing your business', + style: TextStyle( + color: Colors.grey[600], + fontSize: screenWidth / 55, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 40), + _errorMessage != '' + ? Container( + margin: EdgeInsets.only(bottom: 20.0), + padding: EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.red.shade50, + borderRadius: BorderRadius.circular(8.0), + border: Border.all(color: Colors.red.shade200), + ), + child: Row( + children: [ + Icon(Icons.error_outline, color: Colors.red, size: 18), + SizedBox(width: 8), + Expanded( + child: Text( + _errorMessage, + style: TextStyle( + color: Colors.red[700], + fontSize: screenWidth / 60, + ), + ), + ), + ], + ), + ) + : SizedBox(), + !_isLoading + ? Container( + width: double.infinity, + height: 56, + child: ElevatedButton( + onPressed: _googleLogin, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black87, + elevation: 2, + shadowColor: Colors.black26, + side: BorderSide(color: Colors.grey[300]!, width: 1), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/google-icon.png', + width: 24, + height: 24, + ), + SizedBox(width: 16), + Text( + 'Continue with Google', + style: TextStyle( + fontSize: screenWidth / 45, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ) + : Container( + height: 56, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation( + Theme.of(context).primaryColor), + ), + ), + ), + SizedBox(height: 30), + Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.blue.shade50, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.blue.shade200), + ), + child: Row( + children: [ + Icon(Icons.info_outline, color: Colors.blue, size: 18), + SizedBox(width: 8), + Expanded( + child: Text( + 'Secure sign-in powered by Google OAuth 2.0', + style: TextStyle( + color: Colors.blue[700], + fontSize: screenWidth / 65, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + screenWidth = MediaQuery.of(context).size.width; + screenHeight = MediaQuery.of(context).size.height; + return Scaffold( + body: loginWidget(), + ); + } +} diff --git a/lib/ui/screens/modern/authentication/organization_selection_screen.dart b/lib/ui/screens/modern/authentication/organization_selection_screen.dart new file mode 100644 index 0000000..ae2aeb0 --- /dev/null +++ b/lib/ui/screens/modern/authentication/organization_selection_screen.dart @@ -0,0 +1,716 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:bottle_crm/bloc/auth_bloc.dart'; +import 'package:bottle_crm/model/organization.dart'; +import 'package:bottle_crm/responsive.dart'; +import 'package:bottle_crm/utils/utils.dart'; + +class OrganizationSelectionScreen extends StatefulWidget { + const OrganizationSelectionScreen({Key? key}) : super(key: key); + + @override + State createState() => _OrganizationSelectionScreenState(); +} + +class _OrganizationSelectionScreenState extends State + with TickerProviderStateMixin { + List organizations = []; + bool isLoading = false; + int? selectedIndex; + String searchQuery = ''; + late AnimationController _fadeController; + late AnimationController _slideController; + late AnimationController _searchController; + late Animation _fadeAnimation; + late Animation _slideAnimation; + late Animation _searchAnimation; + final TextEditingController _searchTextController = TextEditingController(); + final FocusNode _searchFocusNode = FocusNode(); + + List get filteredOrganizations { + if (searchQuery.isEmpty) return organizations; + return organizations.where((org) => + org.name?.toLowerCase().contains(searchQuery.toLowerCase()) ?? false + ).toList(); + } + + @override + void initState() { + super.initState(); + _setupAnimations(); + _loadOrganizations(); + } + + void _setupAnimations() { + _fadeController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + _slideController = AnimationController( + duration: const Duration(milliseconds: 600), + vsync: this, + ); + _searchController = AnimationController( + duration: const Duration(milliseconds: 400), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _fadeController, + curve: Curves.easeInOut, + )); + + _slideAnimation = Tween( + begin: const Offset(0, 0.3), + end: Offset.zero, + ).animate(CurvedAnimation( + parent: _slideController, + curve: Curves.easeOutCubic, + )); + + _searchAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _searchController, + curve: Curves.easeInOut, + )); + } + + void _loadOrganizations() { + setState(() { + organizations = authBloc.companies; + }); + + // Start animations + _fadeController.forward(); + Future.delayed(const Duration(milliseconds: 200), () { + _slideController.forward(); + }); + Future.delayed(const Duration(milliseconds: 600), () { + _searchController.forward(); + }); + } + + @override + void dispose() { + _fadeController.dispose(); + _slideController.dispose(); + _searchController.dispose(); + _searchTextController.dispose(); + _searchFocusNode.dispose(); + super.dispose(); + } + + Future _selectOrganization(int index) async { + if (isLoading) return; + + // Haptic feedback + HapticFeedback.lightImpact(); + + setState(() { + selectedIndex = index; + isLoading = true; + }); + + try { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('org', organizations[index].id!); + authBloc.selectedOrganization = organizations[index]; + + // Fetch required data + await fetchRequiredData(); + + // Analytics + await FirebaseAnalytics.instance.logEvent( + name: "${organizations[index].name!}_Selected" + ); + + // Navigate with a slight delay for visual feedback + await Future.delayed(const Duration(milliseconds: 300)); + + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + '/dashboard', + (route) => false + ); + } + } catch (e) { + if (mounted) { + setState(() { + selectedIndex = null; + isLoading = false; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to select organization. Please try again.'), + backgroundColor: Colors.red[600], + behavior: SnackBarBehavior.floating, + ), + ); + } + } + } + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) async { + if (!didPop) { + bool shouldPop = await onWillPop(); + if (shouldPop) Navigator.of(context).pop(); + } + }, + child: Scaffold( + backgroundColor: const Color(0xFF4980FF), + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: _buildOrganizationsList(), + ), + ], + ), + ), + ), + ); + } + + Widget _buildHeader() { + return FadeTransition( + opacity: _fadeAnimation, + child: Container( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + Text( + 'Welcome back!', + style: TextStyle( + color: Colors.white.withOpacity(0.9), + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + const SizedBox(height: 8), + Row( + children: [ + const Expanded( + child: Text( + 'Select your organization', + style: TextStyle( + color: Colors.white, + fontSize: 28, + fontWeight: FontWeight.bold, + height: 1.2, + ), + ), + ), + if (organizations.length > 1) + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.white.withOpacity(0.3), + ), + ), + child: Text( + '${organizations.length} available', + style: TextStyle( + color: Colors.white.withOpacity(0.9), + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + 'Choose the organization you want to access', + style: TextStyle( + color: Colors.white.withOpacity(0.8), + fontSize: 16, + height: 1.4, + ), + ), + ], + ), + ), + ); + } + + Widget _buildOrganizationsList() { + return SlideTransition( + position: _slideAnimation, + child: FadeTransition( + opacity: _fadeAnimation, + child: Container( + decoration: const BoxDecoration( + color: Color(0xFFF8F9FA), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), + ), + child: Column( + children: [ + const SizedBox(height: 8), + // Drag indicator + Container( + width: 40, + height: 4, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(2), + ), + ), + const SizedBox(height: 16), + // Search bar (if organizations > 3) + if (organizations.length > 3) _buildSearchBar(), + const SizedBox(height: 8), + Expanded( + child: organizations.isNotEmpty + ? _buildOrganizationsGrid() + : _buildEmptyState(), + ), + ], + ), + ), + ), + ); + } + + Widget _buildSearchBar() { + return SlideTransition( + position: Tween( + begin: const Offset(0, -0.5), + end: Offset.zero, + ).animate(_searchAnimation), + child: FadeTransition( + opacity: _searchAnimation, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 24), + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: _searchFocusNode.hasFocus + ? const Color(0xFF4980FF).withOpacity(0.3) + : Colors.transparent, + ), + ), + child: Row( + children: [ + Icon( + Icons.search, + color: Colors.grey[600], + size: 20, + ), + const SizedBox(width: 12), + Expanded( + child: TextField( + controller: _searchTextController, + focusNode: _searchFocusNode, + onChanged: (value) { + setState(() { + searchQuery = value; + }); + }, + decoration: const InputDecoration( + hintText: 'Search organizations...', + border: InputBorder.none, + hintStyle: TextStyle( + fontSize: 16, + color: Colors.grey, + ), + ), + style: const TextStyle( + fontSize: 16, + color: Colors.black87, + ), + ), + ), + if (searchQuery.isNotEmpty) + GestureDetector( + onTap: () { + _searchTextController.clear(); + setState(() { + searchQuery = ''; + }); + }, + child: Icon( + Icons.clear, + color: Colors.grey[600], + size: 20, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildOrganizationsGrid() { + final orgsToShow = filteredOrganizations; + + if (orgsToShow.isEmpty && searchQuery.isNotEmpty) { + return _buildNoSearchResults(); + } + + return Responsive( + mobile: _buildMobileList(orgsToShow), + tablet: _buildTabletGrid(orgsToShow), + desktop: _buildDesktopGrid(orgsToShow), + ); + } + + Widget _buildMobileList(List orgs) { + return ListView.builder( + padding: const EdgeInsets.symmetric(horizontal: 24), + itemCount: orgs.length, + itemBuilder: (context, index) { + final orgIndex = organizations.indexOf(orgs[index]); + return AnimatedContainer( + duration: Duration(milliseconds: 100 + (index * 50)), + curve: Curves.easeOutBack, + child: _buildOrganizationCard(orgIndex, true, orgs[index]), + ); + }, + ); + } + + Widget _buildTabletGrid(List orgs) { + return GridView.builder( + padding: const EdgeInsets.symmetric(horizontal: 24), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + childAspectRatio: 2.5, + ), + itemCount: orgs.length, + itemBuilder: (context, index) { + final orgIndex = organizations.indexOf(orgs[index]); + return AnimatedContainer( + duration: Duration(milliseconds: 100 + (index * 50)), + curve: Curves.easeOutBack, + child: _buildOrganizationCard(orgIndex, false, orgs[index]), + ); + }, + ); + } + + Widget _buildDesktopGrid(List orgs) { + return GridView.builder( + padding: const EdgeInsets.symmetric(horizontal: 32), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 20, + mainAxisSpacing: 20, + childAspectRatio: 2.2, + ), + itemCount: orgs.length, + itemBuilder: (context, index) { + final orgIndex = organizations.indexOf(orgs[index]); + return AnimatedContainer( + duration: Duration(milliseconds: 100 + (index * 50)), + curve: Curves.easeOutBack, + child: _buildOrganizationCard(orgIndex, false, orgs[index]), + ); + }, + ); + } + + Widget _buildOrganizationCard(int index, bool isList, Organization organization) { + final isSelected = selectedIndex == index; + final isAdmin = organization.role == 'ADMIN'; + + return AnimatedContainer( + duration: const Duration(milliseconds: 200), + margin: EdgeInsets.only(bottom: isList ? 16 : 0), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => _selectOrganization(index), + borderRadius: BorderRadius.circular(20), + child: AnimatedContainer( + duration: const Duration(milliseconds: 200), + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFF4980FF) : Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isSelected + ? const Color(0xFF4980FF) + : Colors.grey.withOpacity(0.1), + width: isSelected ? 2 : 1, + ), + boxShadow: [ + BoxShadow( + color: isSelected + ? const Color(0xFF4980FF).withOpacity(0.3) + : Colors.black.withOpacity(0.04), + blurRadius: isSelected ? 20 : 8, + offset: Offset(0, isSelected ? 8 : 2), + ), + ], + ), + child: Row( + children: [ + // Organization Avatar + Container( + width: 56, + height: 56, + decoration: BoxDecoration( + color: isSelected + ? Colors.white.withOpacity(0.2) + : const Color(0xFF4980FF).withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + ), + child: Center( + child: Text( + organization.name?.isNotEmpty == true + ? organization.name![0].toUpperCase() + : '?', + style: TextStyle( + color: isSelected + ? Colors.white + : const Color(0xFF4980FF), + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(width: 16), + // Organization Info + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + organization.name ?? 'Unknown Organization', + style: TextStyle( + color: isSelected ? Colors.white : Colors.grey[800], + fontSize: 18, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: isSelected + ? Colors.white.withOpacity(0.2) + : isAdmin + ? const Color(0xFF10B981).withOpacity(0.1) + : Colors.grey.withOpacity(0.1), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: isSelected + ? Colors.white.withOpacity(0.3) + : isAdmin + ? const Color(0xFF10B981).withOpacity(0.3) + : Colors.grey.withOpacity(0.3), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + isAdmin ? Icons.admin_panel_settings : Icons.person, + size: 14, + color: isSelected + ? Colors.white + : isAdmin + ? const Color(0xFF10B981) + : Colors.grey[600], + ), + const SizedBox(width: 4), + Text( + organization.role ?? 'USER', + style: TextStyle( + color: isSelected + ? Colors.white + : isAdmin + ? const Color(0xFF10B981) + : Colors.grey[600], + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ), + ), + // Loading indicator or arrow + if (isLoading && isSelected) + const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + else + Icon( + Icons.arrow_forward_ios, + color: isSelected + ? Colors.white.withOpacity(0.8) + : Colors.grey[400], + size: 16, + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildNoSearchResults() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 120, + height: 120, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(60), + ), + child: Icon( + Icons.search_off_outlined, + size: 60, + color: Colors.grey[400], + ), + ), + const SizedBox(height: 24), + Text( + 'No Results Found', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 8), + Text( + 'Try adjusting your search terms\nor check the spelling.', + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + height: 1.5, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + OutlinedButton.icon( + onPressed: () { + _searchTextController.clear(); + setState(() { + searchQuery = ''; + }); + }, + icon: const Icon(Icons.clear_all), + label: const Text('Clear Search'), + style: OutlinedButton.styleFrom( + foregroundColor: const Color(0xFF4980FF), + side: const BorderSide(color: Color(0xFF4980FF)), + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ], + ), + ); + } + + Widget _buildEmptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 120, + height: 120, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(60), + ), + child: Icon( + Icons.business_outlined, + size: 60, + color: Colors.grey[400], + ), + ), + const SizedBox(height: 24), + Text( + 'No Organizations Found', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 8), + Text( + 'Please contact your administrator to get access\nto an organization.', + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + height: 1.5, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + OutlinedButton.icon( + onPressed: () { + Navigator.pushNamedAndRemoveUntil( + context, + '/login', + (route) => false, + ); + }, + icon: const Icon(Icons.refresh), + label: const Text('Try Again'), + style: OutlinedButton.styleFrom( + foregroundColor: const Color(0xFF4980FF), + side: const BorderSide(color: Color(0xFF4980FF)), + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/screens/modern/dashboard_controller.dart b/lib/ui/screens/modern/dashboard_controller.dart new file mode 100644 index 0000000..b27b598 --- /dev/null +++ b/lib/ui/screens/modern/dashboard_controller.dart @@ -0,0 +1,134 @@ +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:bottle_crm/model/account.dart'; +import 'package:bottle_crm/model/contact.dart'; +import 'package:bottle_crm/model/opportunities.dart'; +import 'package:bottle_crm/services/crm_services.dart'; +import 'dashboard_state.dart'; + +class DashboardController extends ChangeNotifier { + DashboardState _state = DashboardInitial(); + + DashboardState get state => _state; + + bool get isLoading => _state is DashboardLoading; + bool get hasError => _state is DashboardError; + bool get hasData => _state is DashboardLoaded; + bool get isEmpty => _state is DashboardEmpty; + + DashboardLoaded? get data => _state is DashboardLoaded ? _state as DashboardLoaded : null; + String get errorMessage => _state is DashboardError ? (_state as DashboardError).message : ''; + + void _setState(DashboardState newState) { + _state = newState; + notifyListeners(); + } + + Future loadDashboard() async { + if (_state is DashboardLoading) return; // Prevent multiple loading calls + + _setState(DashboardLoading()); + + try { + final response = await CrmService().getDashboardDetails(); + final res = json.decode(response.body); + + if (response.statusCode != 200) { + throw Exception('Failed to load dashboard: ${response.statusCode}'); + } + + // Parse accounts + final List accounts = []; + if (res['accounts'] != null) { + for (var accountData in res['accounts']) { + try { + accounts.add(Account.fromJson(accountData)); + } catch (e) { + debugPrint('Error parsing account: $e'); + } + } + } + + // Parse contacts + final List contacts = []; + if (res['contacts'] != null) { + for (var contactData in res['contacts']) { + try { + contacts.add(Contact.fromJson(contactData)); + } catch (e) { + debugPrint('Error parsing contact: $e'); + } + } + } + + // Parse opportunities + final List opportunities = []; + if (res['opportunities'] != null) { + for (var opportunityData in res['opportunities']) { + try { + opportunities.add(Opportunity.fromJson(opportunityData)); + } catch (e) { + debugPrint('Error parsing opportunity: $e'); + } + } + } + + // Check if all data is empty + final accountsCount = res['accounts_count'] ?? 0; + final contactsCount = res['contacts_count'] ?? 0; + final leadsCount = res['leads_count'] ?? 0; + final opportunitiesCount = res['opportunities_count'] ?? 0; + + final totalCount = accountsCount + contactsCount + leadsCount + opportunitiesCount; + + if (totalCount == 0 && accounts.isEmpty && contacts.isEmpty && opportunities.isEmpty) { + _setState(DashboardEmpty()); + return; + } + + _setState(DashboardLoaded( + accounts: accounts, + contacts: contacts, + opportunities: opportunities, + accountsCount: accountsCount, + contactsCount: contactsCount, + leadsCount: leadsCount, + opportunitiesCount: opportunitiesCount, + )); + + } catch (e) { + debugPrint('Dashboard loading error: $e'); + String errorMessage = 'Failed to load dashboard data'; + + if (e.toString().contains('Network')) { + errorMessage = 'Network error. Please check your connection.'; + } else if (e.toString().contains('401')) { + errorMessage = 'Authentication error. Please log in again.'; + } else if (e.toString().contains('403')) { + errorMessage = 'Access denied. Please check your permissions.'; + } else if (e.toString().contains('500')) { + errorMessage = 'Server error. Please try again later.'; + } + + _setState(DashboardError(errorMessage, e is Exception ? e : Exception(e.toString()))); + } + } + + Future refresh() async { + await loadDashboard(); + } + + void clearError() { + if (_state is DashboardError) { + _setState(DashboardInitial()); + } + } + + // Helper methods for backward compatibility with existing dashboard bloc + Map get dashboardData { + if (_state is DashboardLoaded) { + return (_state as DashboardLoaded).toMap(); + } + return {}; + } +} \ No newline at end of file diff --git a/lib/ui/screens/modern/dashboard_screen.dart b/lib/ui/screens/modern/dashboard_screen.dart new file mode 100644 index 0000000..4f7769c --- /dev/null +++ b/lib/ui/screens/modern/dashboard_screen.dart @@ -0,0 +1,547 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:bottle_crm/responsive.dart'; +import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; +import 'dashboard_controller.dart'; + +class ModernDashboardScreen extends StatefulWidget { + const ModernDashboardScreen({Key? key}) : super(key: key); + + @override + State createState() => _ModernDashboardScreenState(); +} + +class _ModernDashboardScreenState extends State + with TickerProviderStateMixin { + late TabController _tabController; + late DashboardController _dashboardController; + + @override + void initState() { + super.initState(); + _tabController = TabController(length: 3, vsync: this); + _dashboardController = DashboardController(); + _dashboardController.addListener(_onDashboardStateChanged); + _loadDashboardData(); + } + + @override + void dispose() { + _tabController.dispose(); + _dashboardController.removeListener(_onDashboardStateChanged); + _dashboardController.dispose(); + super.dispose(); + } + + void _onDashboardStateChanged() { + if (mounted) { + setState(() {}); + } + } + + Future _loadDashboardData() async { + await _dashboardController.loadDashboard(); + } + + @override + Widget build(BuildContext context) { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown + ]); + + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + if (!didPop) { + Navigator.pushNamedAndRemoveUntil( + context, '/organization_selection', (route) => false); + } + }, + child: Scaffold( + backgroundColor: const Color(0xFFF8F9FA), + appBar: _buildAppBar(), + body: RefreshIndicator( + onRefresh: _loadDashboardData, + child: _dashboardController.isLoading + ? const Center(child: CircularProgressIndicator()) + : _dashboardController.hasError + ? _buildErrorState() + : _dashboardController.isEmpty + ? _buildEmptyDashboard() + : _buildDashboardContent(), + ), + bottomNavigationBar: BottomNavigationBarWidget(), + ), + ); + } + + PreferredSizeWidget _buildAppBar() { + return AppBar( + elevation: 0, + backgroundColor: const Color(0xFF4980FF), + systemOverlayStyle: SystemUiOverlayStyle.light, + title: const Text( + 'Dashboard', + style: TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.w600, + ), + ), + automaticallyImplyLeading: false, + actions: [ + IconButton( + icon: const Icon(Icons.refresh, color: Colors.white), + onPressed: _loadDashboardData, + ), + ], + ); + } + + Widget _buildErrorState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.error_outline, + size: 64, + color: Colors.grey[400], + ), + const SizedBox(height: 16), + Text( + _dashboardController.errorMessage, + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + ElevatedButton( + onPressed: _loadDashboardData, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF4980FF), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text('Retry'), + ), + ], + ), + ); + } + + Widget _buildEmptyDashboard() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.dashboard_outlined, + size: 64, + color: Colors.grey[400], + ), + const SizedBox(height: 16), + Text( + 'Welcome to BottleCRM!', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey[700], + ), + ), + const SizedBox(height: 8), + Text( + 'Start by adding your first account, contact, or lead', + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + ElevatedButton( + onPressed: () => Navigator.pushNamed(context, '/accounts_list'), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF4980FF), + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text('Get Started'), + ), + ], + ), + ); + } + + Widget _buildDashboardContent() { + return Responsive( + mobile: _buildMobileLayout(), + tablet: _buildTabletLayout(), + desktop: _buildDesktopLayout(), + ); + } + + Widget _buildMobileLayout() { + return SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildStatsGrid(), + const SizedBox(height: 24), + _buildRecentSection(), + ], + ), + ); + } + + Widget _buildTabletLayout() { + return SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.all(24), + child: Column( + children: [ + _buildStatsGrid(), + const SizedBox(height: 32), + _buildRecentSection(), + ], + ), + ); + } + + Widget _buildDesktopLayout() { + return SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + padding: const EdgeInsets.all(32), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 2, + child: Column( + children: [ + _buildStatsGrid(), + const SizedBox(height: 32), + ], + ), + ), + const SizedBox(width: 32), + Expanded( + flex: 3, + child: _buildRecentSection(), + ), + ], + ), + ); + } + + Widget _buildStatsGrid() { + final isMobile = Responsive.isMobile(context); + + return GridView.count( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + crossAxisCount: isMobile ? 2 : 4, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + childAspectRatio: isMobile ? 1.2 : 1.1, + children: [ + _buildModernStatCard( + label: 'Accounts', + count: _dashboardController.data?.accountsCount ?? 0, + icon: 'assets/images/accounts_color.svg', + color: const Color(0xFF4CAF50), + onTap: () => Navigator.pushNamed(context, '/accounts_list'), + ), + _buildModernStatCard( + label: 'Contacts', + count: _dashboardController.data?.contactsCount ?? 0, + icon: 'assets/images/identification.svg', + color: const Color(0xFF2196F3), + onTap: () => Navigator.pushNamed(context, '/contacts_list'), + ), + _buildModernStatCard( + label: 'Leads', + count: _dashboardController.data?.leadsCount ?? 0, + icon: 'assets/images/flag.svg', + color: const Color(0xFFFF9800), + onTap: () => Navigator.pushNamed(context, '/leads_list'), + ), + _buildModernStatCard( + label: 'Opportunities', + count: _dashboardController.data?.opportunitiesCount ?? 0, + icon: 'assets/images/opportunities_color.svg', + color: const Color(0xFF9C27B0), + onTap: () => Navigator.pushNamed(context, '/opportunities_list'), + ), + ], + ); + } + + Widget _buildModernStatCard({ + required String label, + required int count, + required String icon, + required Color color, + required VoidCallback onTap, + }) { + return Material( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + elevation: 2, + shadowColor: Colors.black.withOpacity(0.05), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(16), + child: Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + border: Border.all(color: color.withOpacity(0.1)), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: color.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Center( + child: SvgPicture.asset( + icon, + width: 24, + height: 24, + colorFilter: ColorFilter.mode(color, BlendMode.srcIn), + ), + ), + ), + const SizedBox(height: 12), + Text( + count.toString(), + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 4), + Text( + label, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ), + ); + } + + Widget _buildRecentSection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Recent Activity', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 16), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + children: [ + TabBar( + controller: _tabController, + indicator: UnderlineTabIndicator( + borderSide: const BorderSide( + width: 3, + color: Color(0xFF4980FF), + ), + insets: const EdgeInsets.symmetric(horizontal: 16), + ), + labelColor: const Color(0xFF4980FF), + unselectedLabelColor: Colors.grey[600], + labelStyle: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + unselectedLabelStyle: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 14, + ), + tabs: const [ + Tab(text: 'Accounts'), + Tab(text: 'Contacts'), + Tab(text: 'Opportunities'), + ], + ), + SizedBox( + height: 400, + child: TabBarView( + controller: _tabController, + children: [ + _buildRecentList('accounts'), + _buildRecentList('contacts'), + _buildRecentList('opportunities'), + ], + ), + ), + ], + ), + ), + ], + ); + } + + Widget _buildRecentList(String type) { + List? data; + + switch (type) { + case 'accounts': + data = _dashboardController.data?.accounts; + break; + case 'contacts': + data = _dashboardController.data?.contacts; + break; + case 'opportunities': + data = _dashboardController.data?.opportunities; + break; + } + + if (data == null || data.isEmpty) { + return _buildEmptyState(type); + } + + return ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: data.length, + separatorBuilder: (context, index) => const Divider(height: 1), + itemBuilder: (context, index) { + return _buildRecentListItem(data![index], type); + }, + ); + } + + Widget _buildEmptyState(String type) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.inbox_outlined, + size: 48, + color: Colors.grey[400], + ), + const SizedBox(height: 16), + Text( + 'No recent $type', + style: TextStyle( + fontSize: 16, + color: Colors.grey[600], + ), + ), + ], + ), + ); + } + + Widget _buildRecentListItem(dynamic item, String type) { + String name = ''; + String subtitle = ''; + String? imageUrl; + + switch (type) { + case 'accounts': + name = item.name ?? ''; + subtitle = item.email ?? ''; + imageUrl = item.createdBy?.profileUrl; + break; + case 'contacts': + name = '${item.firstName ?? ''} ${item.lastName ?? ''}'.trim(); + subtitle = item.primaryEmail ?? ''; + imageUrl = item.createdBy?.profileUrl; + break; + case 'opportunities': + name = item.name ?? ''; + subtitle = item.amount?.toString() ?? ''; + imageUrl = item.createdBy?.profileUrl; + break; + } + + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + leading: CircleAvatar( + radius: 20, + backgroundColor: const Color(0xFF4980FF).withOpacity(0.1), + backgroundImage: imageUrl != null ? NetworkImage(imageUrl) : null, + child: imageUrl == null + ? Text( + name.isNotEmpty ? name[0].toUpperCase() : '?', + style: const TextStyle( + color: Color(0xFF4980FF), + fontWeight: FontWeight.w600, + ), + ) + : null, + ), + title: Text( + name, + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + subtitle: subtitle.isNotEmpty + ? Text( + subtitle, + style: TextStyle( + color: Colors.grey[600], + fontSize: 12, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ) + : null, + trailing: Icon( + Icons.chevron_right, + color: Colors.grey[400], + size: 20, + ), + onTap: () { + // TODO: Navigate to detail screen + }, + ); + } +} \ No newline at end of file diff --git a/lib/ui/screens/modern/dashboard_state.dart b/lib/ui/screens/modern/dashboard_state.dart new file mode 100644 index 0000000..b7d4baf --- /dev/null +++ b/lib/ui/screens/modern/dashboard_state.dart @@ -0,0 +1,52 @@ +import 'package:flutter/foundation.dart'; +import 'package:bottle_crm/model/account.dart'; +import 'package:bottle_crm/model/contact.dart'; +import 'package:bottle_crm/model/opportunities.dart'; + +@immutable +sealed class DashboardState {} + +class DashboardInitial extends DashboardState {} + +class DashboardLoading extends DashboardState {} + +class DashboardLoaded extends DashboardState { + final List accounts; + final List contacts; + final List opportunities; + final int accountsCount; + final int contactsCount; + final int leadsCount; + final int opportunitiesCount; + + DashboardLoaded({ + required this.accounts, + required this.contacts, + required this.opportunities, + required this.accountsCount, + required this.contactsCount, + required this.leadsCount, + required this.opportunitiesCount, + }); + + Map toMap() { + return { + 'accounts': accounts, + 'contacts': contacts, + 'opportunities': opportunities, + 'accountsCount': accountsCount, + 'contactsCount': contactsCount, + 'leadsCount': leadsCount, + 'opportunitiesCount': opportunitiesCount, + }; + } +} + +class DashboardError extends DashboardState { + final String message; + final Exception? exception; + + DashboardError(this.message, [this.exception]); +} + +class DashboardEmpty extends DashboardState {} \ No newline at end of file diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index b12f04b..af6d60a 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -2,7 +2,6 @@ import 'dart:io'; import 'dart:math'; import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/bloc/auth_bloc.dart'; import 'package:bottle_crm/bloc/case_bloc.dart'; import 'package:bottle_crm/bloc/contact_bloc.dart'; import 'package:bottle_crm/bloc/dashboard_bloc.dart'; @@ -61,7 +60,7 @@ SimpleRandomColor randomColor = SimpleRandomColor(); fetchRequiredData() async { print("fetching data ▁ ▂ ▃ ▄ ▅ ▆"); - await authBloc.getProfileDetails(); + // Profile data already fetched during login - no need to fetch again await dashboardBloc.fetchDashboardDetails(); await leadBloc.fetchLeads(); await accountBloc.fetchAccounts(); From 98e25332a5ff3791ef719d3ef181cbc498fb7397 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Thu, 31 Jul 2025 21:21:59 +0530 Subject: [PATCH 6/9] feat: Add google-services.json to .gitignore to prevent sensitive data exposure --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 37b1568..f8610a6 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# Add this line to .gitignore +android/app/google-services.json \ No newline at end of file From e350a3cee1a34d0116db06c2956a44ea16d80391 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Thu, 31 Jul 2025 21:24:45 +0530 Subject: [PATCH 7/9] feat: Update .gitignore to include additional sensitive files and configuration settings --- .gitignore | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f8610a6..1c09cfb 100644 --- a/.gitignore +++ b/.gitignore @@ -47,5 +47,66 @@ app.*.map.json /android/app/profile /android/app/release -# Add this line to .gitignore -android/app/google-services.json \ No newline at end of file +# Firebase & Security Sensitive Files +android/app/google-services.json +ios/Runner/GoogleService-Info.plist +ios/firebase_app_id_file.json + +# Environment & Configuration Files +.env +.env.local +.env.production +.env.development +config.json +secrets.json + +# API Keys & Credentials +**/api_keys.dart +**/secrets.dart +**/credentials.json +**/service-account-key.json + +# Keystore Files (Android signing) +*.keystore +*.jks +key.properties +android/key.properties + +# iOS Signing & Certificates +ios/Runner/GoogleService-Info.plist +ios/Runner.xcodeproj/project.xcworkspace/xcuserdata/ +ios/Runner.xcodeproj/xcuserdata/ +ios/Pods/ +ios/.symlinks/ +*.mobileprovision +*.p12 +*.cer + +# Local Development +local.properties +android/local.properties + +# IDE & Editor +.vscode/settings.json +.vscode/launch.json +*.code-workspace + +# OS Generated +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# Temporary Files +*.tmp +*.temp +*.bak +*.swp +*~ + +# Log Files +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* From 4022180cd09149b143873fc8088cdf4dee03b408 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Fri, 1 Aug 2025 17:59:15 +0530 Subject: [PATCH 8/9] Remove sensitive configuration files --- android/app/google-services.json | 47 -------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 android/app/google-services.json diff --git a/android/app/google-services.json b/android/app/google-services.json deleted file mode 100644 index b84d2a1..0000000 --- a/android/app/google-services.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "project_info": { - "project_number": "1072513761792", - "project_id": "bottlecrm-io", - "storage_bucket": "bottlecrm-io.firebasestorage.app" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:1072513761792:android:aa69724adcb7121fd74ee5", - "android_client_info": { - "package_name": "io.bottlecrm" - } - }, - "oauth_client": [ - { - "client_id": "1072513761792-raut9sdi00i87j81o4irmiha3fd5pmvc.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "io.bottlecrm", - "certificate_hash": "67c4be5a9739470b402c1405f181abc7e6cfa7df" - } - }, - { - "client_id": "1072513761792-dvcv8cj147oj6nav40u7jfjp1r3f0a1d.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyDsA2wgQIw-bVgwODNMIF482gVRn5xdANU" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "1072513761792-dvcv8cj147oj6nav40u7jfjp1r3f0a1d.apps.googleusercontent.com", - "client_type": 3 - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file From 88ff466a5582b2a863b99eb10e80e011f8a62d47 Mon Sep 17 00:00:00 2001 From: Ashwin Date: Fri, 1 Aug 2025 18:01:19 +0530 Subject: [PATCH 9/9] Add Windows runner and Flutter integration - Introduced CMake configuration for Windows Flutter application in `CMakeLists.txt`. - Created `generated_plugin_registrant` files for plugin registration. - Implemented the main application entry point in `main.cpp` and window management in `flutter_window.cpp` and `win32_window.cpp`. - Added resource files including application icon and manifest for Windows compatibility. - Established utility functions for console management and command line argument handling. - Ensured proper DPI scaling and theme support for the application window. - Set up build dependencies and linked necessary libraries for Flutter integration. --- .flutter-plugins-dependencies | 2 +- .gitignore | 13 +- CLAUDE.md | 299 ++- FIREBASE_SETUP.md | 28 + README.md | 587 +++++- REFACTORING_PLAN.md | 174 -- analysis_options.yaml | 28 + android/.gitignore | 5 +- android/app/build.gradle | 70 - android/app/build.gradle.kts | 69 + android/app/src/debug/AndroidManifest.xml | 6 +- android/app/src/main/AndroidManifest.xml | 40 +- .../main/kotlin/io/bottlecrm/MainActivity.kt | 3 +- .../main/res/mipmap-hdpi/launcher_icon.png | Bin 1686 -> 3500 bytes .../main/res/mipmap-mdpi/launcher_icon.png | Bin 1045 -> 1815 bytes .../main/res/mipmap-xhdpi/launcher_icon.png | Bin 2290 -> 6133 bytes .../main/res/mipmap-xxhdpi/launcher_icon.png | Bin 3459 -> 14966 bytes .../main/res/mipmap-xxxhdpi/launcher_icon.png | Bin 4459 -> 28411 bytes .../app/src/main/res/values-night/styles.xml | 6 +- android/app/src/main/res/values/styles.xml | 7 +- android/app/src/profile/AndroidManifest.xml | 6 +- android/build.gradle | 50 - android/build.gradle.kts | 31 + android/gradle.properties | 5 +- .../gradle/wrapper/gradle-wrapper.properties | 3 +- android/settings.gradle | 26 - android/settings.gradle.kts | 25 + android/settings_aar.gradle | 1 - assets/icon/icon.png | Bin 0 -> 250131 bytes assets/images/Icon_edit_color.svg | 3 - assets/images/accounts.svg | 7 - assets/images/accounts_color.svg | 7 - assets/images/arrow_backward.svg | 3 - assets/images/arrow_forward.svg | 3 - assets/images/bg-image-blue.jpg | Bin 44377 -> 0 bytes assets/images/bg-image.png | Bin 289333 -> 0 bytes assets/images/cases.svg | 3 - assets/images/change_password.svg | 6 - assets/images/contacts.svg | 10 - assets/images/dashboard_icon.svg | 17 - assets/images/documents.svg | 3 - assets/images/download_icon.svg | 1 - assets/images/events.svg | 3 - assets/images/filter.svg | 7 - assets/images/flag.svg | 5 - assets/images/google-icon.png | Bin 6819 -> 0 bytes assets/images/home.svg | 5 - assets/images/icon_close.svg | 3 - assets/images/icon_delete_color.svg | 8 - assets/images/identification.svg | 10 - assets/images/invoices.svg | 9 - assets/images/leads.svg | 10 - assets/images/logo.svg | 81 - assets/images/logo_google.svg | 3 - assets/images/logout.svg | 7 - assets/images/menu.svg | 9 - assets/images/more.svg | 9 - assets/images/new_logo.png | Bin 14571 -> 0 bytes assets/images/opportunities.svg | 15 - assets/images/opportunities_color.svg | 12 - assets/images/pdf_icon.svg | 51 - assets/images/search.svg | 8 - assets/images/settings.svg | 3 - assets/images/skype.png | Bin 917 -> 0 bytes assets/images/tasks.svg | 13 - assets/images/teams.svg | 3 - assets/images/users.svg | 7 - devtools_options.yaml | 3 + ios/.gitignore | 1 + ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Flutter/Debug.xcconfig | 1 - ios/Flutter/Release.xcconfig | 1 - ios/Podfile | 41 - ios/Podfile.lock | 85 - ios/Runner.xcodeproj/project.pbxproj | 221 ++- .../xcshareddata/xcschemes/Runner.xcscheme | 24 +- .../contents.xcworkspacedata | 3 - ios/Runner/AppDelegate.swift | 4 +- .../AppIcon.appiconset/Contents.json | 123 +- .../Icon-App-1024x1024@1x.png | Bin 33004 -> 480618 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 395 -> 541 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 891 -> 1291 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1359 -> 2388 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 587 -> 840 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1273 -> 2237 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 2045 -> 4616 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 891 -> 1291 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1931 -> 3902 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2831 -> 9056 bytes .../AppIcon.appiconset/Icon-App-50x50@1x.png | Bin 0 -> 1750 bytes .../AppIcon.appiconset/Icon-App-50x50@2x.png | Bin 0 -> 6143 bytes .../AppIcon.appiconset/Icon-App-57x57@1x.png | Bin 0 -> 2153 bytes .../AppIcon.appiconset/Icon-App-57x57@2x.png | Bin 0 -> 8188 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2831 -> 9056 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 4178 -> 21953 bytes .../AppIcon.appiconset/Icon-App-72x72@1x.png | Bin 0 -> 3237 bytes .../AppIcon.appiconset/Icon-App-72x72@2x.png | Bin 0 -> 13517 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1814 -> 3507 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3668 -> 15136 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3982 -> 18529 bytes ios/Runner/Info.plist | 8 +- ios/RunnerTests/RunnerTests.swift | 12 + lib/app.dart | 158 ++ lib/bloc/account_bloc.dart | 331 ---- lib/bloc/auth_bloc.dart | 215 --- lib/bloc/case_bloc.dart | 318 --- lib/bloc/contact_bloc.dart | 366 ---- lib/bloc/dashboard_bloc.dart | 51 - lib/bloc/document_bloc.dart | 212 -- lib/bloc/event_bloc.dart | 235 --- lib/bloc/lead_bloc.dart | 406 ---- lib/bloc/opportunity_bloc.dart | 394 ---- lib/bloc/setting_bloc.dart | 318 --- lib/bloc/task_bloc.dart | 273 --- lib/bloc/team_bloc.dart | 203 -- lib/bloc/user_bloc.dart | 251 --- lib/config/api_config.dart | 124 +- lib/main.dart | 135 +- lib/model/account.dart | 133 -- lib/model/case.dart | 105 - lib/model/company.dart | 36 - lib/model/contact.dart | 185 -- lib/model/document.dart | 66 - lib/model/domain.dart | 38 - lib/model/email.dart | 38 - lib/model/events.dart | 94 - lib/model/lead.dart | 151 -- lib/model/opportunities.dart | 141 -- lib/model/organization.dart | 17 - lib/model/profile.dart | 98 - lib/model/settings.dart | 60 - lib/model/task.dart | 81 - lib/model/team.dart | 68 - lib/model/user.dart | 121 -- lib/models/api_models.dart | 1541 +++++++++++++++ lib/responsive.dart | 47 - lib/screens/about_screen.dart | 760 ++++++++ lib/screens/company_create_screen.dart | 190 ++ lib/screens/company_selection_screen.dart | 309 +++ lib/screens/contact_create_screen.dart | 398 ++++ lib/screens/contact_detail_screen.dart | 608 ++++++ lib/screens/contacts_list_screen.dart | 421 ++++ lib/screens/dashboard_screen.dart | 849 ++++++++ lib/screens/help_support_screen.dart | 652 +++++++ lib/screens/lead_create_screen.dart | 422 ++++ lib/screens/lead_detail_screen.dart | 891 +++++++++ lib/screens/leads_list_screen.dart | 837 ++++++++ lib/screens/login_screen.dart | 422 ++++ lib/screens/task_create_screen.dart | 509 +++++ lib/screens/task_detail_screen.dart | 716 +++++++ lib/screens/task_edit_screen.dart | 694 +++++++ lib/screens/tasks_list_screen.dart | 775 ++++++++ lib/services/api_service.dart | 281 +++ lib/services/auth_service.dart | 457 +++++ lib/services/contacts_service.dart | 169 ++ lib/services/crm_services.dart | 1040 ---------- lib/services/dashboard_service.dart | 42 + lib/services/leads_service.dart | 254 +++ lib/services/network_services.dart | 217 --- lib/services/tasks_service.dart | 176 ++ lib/ui/screens/accounts/account_create.dart | 1437 -------------- lib/ui/screens/accounts/account_details.dart | 789 -------- lib/ui/screens/accounts/accounts_list.dart | 699 ------- .../authentication/change_password.dart | 407 ---- .../authentication/companies_List.dart | 189 -- .../authentication/forgot_password.dart | 381 ---- lib/ui/screens/authentication/login.dart | 489 ----- lib/ui/screens/authentication/profile.dart | 256 --- lib/ui/screens/authentication/register.dart | 929 --------- lib/ui/screens/cases/case_create.dart | 953 --------- lib/ui/screens/cases/case_details.dart | 800 -------- lib/ui/screens/cases/cases_list.dart | 599 ------ lib/ui/screens/contacts/contact_create.dart | 1426 -------------- lib/ui/screens/contacts/contact_details.dart | 739 ------- lib/ui/screens/contacts/contacts_list.dart | 488 ----- lib/ui/screens/dashboard/dashboard.dart | 403 ---- lib/ui/screens/documents/document_create.dart | 0 .../screens/documents/document_details.dart | 0 lib/ui/screens/documents/documents_list.dart | 27 - lib/ui/screens/events/event_create.dart | 994 ---------- lib/ui/screens/events/event_details.dart | 614 ------ lib/ui/screens/events/events_list.dart | 221 --- lib/ui/screens/http_excepion.dart | 10 - lib/ui/screens/invoices/invoice_create.dart | 0 lib/ui/screens/invoices/invoice_details.dart | 0 lib/ui/screens/invoices/invoices_list.dart | 27 - lib/ui/screens/leads/lead_create.dart | 1715 ----------------- lib/ui/screens/leads/lead_details.dart | 917 --------- lib/ui/screens/leads/leads_list.dart | 868 --------- .../modern/authentication/login_screen.dart | 490 ----- .../organization_selection_screen.dart | 716 ------- .../screens/modern/dashboard_controller.dart | 134 -- lib/ui/screens/modern/dashboard_screen.dart | 547 ------ lib/ui/screens/modern/dashboard_state.dart | 52 - lib/ui/screens/more_options_screen.dart | 319 --- .../opportunities/opportunitie_create.dart | 1024 ---------- .../opportunitie_create.dart.bak | 1024 ---------- .../opportunities/opportunitie_details.dart | 839 -------- .../opportunities/opportunities_list.dart | 780 -------- lib/ui/screens/settings/settings.dart | 424 ---- lib/ui/screens/settings/settings_details.dart | 498 ----- .../settings/settings_userDetails.dart | 512 ----- lib/ui/screens/tasks/task_create.dart | 867 --------- lib/ui/screens/tasks/task_details.dart | 583 ------ lib/ui/screens/tasks/tasks_list.dart | 570 ------ lib/ui/screens/teams/team_create.dart | 516 ----- lib/ui/screens/teams/team_details.dart | 523 ----- lib/ui/screens/teams/teams_list.dart | 562 ------ lib/ui/screens/users/user_create.dart | 1222 ------------ lib/ui/screens/users/user_details.dart | 581 ------ lib/ui/screens/users/users_list.dart | 427 ---- lib/ui/widgets/bottom_navigation_bar.dart | 212 -- lib/ui/widgets/dashboard_count_card.dart | 79 - lib/ui/widgets/loader.dart | 17 - lib/ui/widgets/profile_pic_widget.dart | 49 - lib/ui/widgets/recent_card_widget.dart | 97 - lib/ui/widgets/tags_widget.dart | 39 - lib/utils/utils.dart | 135 -- lib/utils/validations.dart | 18 - linux/.gitignore | 1 + linux/CMakeLists.txt | 128 ++ linux/flutter/CMakeLists.txt | 88 + linux/flutter/generated_plugin_registrant.cc | 11 + linux/flutter/generated_plugin_registrant.h | 15 + linux/flutter/generated_plugins.cmake | 23 + linux/runner/CMakeLists.txt | 26 + linux/runner/main.cc | 6 + linux/runner/my_application.cc | 130 ++ linux/runner/my_application.h | 18 + macos/.gitignore | 7 + macos/Flutter/Flutter-Debug.xcconfig | 1 + macos/Flutter/Flutter-Release.xcconfig | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 16 + macos/Runner.xcodeproj/project.pbxproj | 705 +++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 99 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + macos/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 68 + .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes macos/Runner/Base.lproj/MainMenu.xib | 343 ++++ macos/Runner/Configs/AppInfo.xcconfig | 14 + macos/Runner/Configs/Debug.xcconfig | 2 + macos/Runner/Configs/Release.xcconfig | 2 + macos/Runner/Configs/Warnings.xcconfig | 13 + macos/Runner/DebugProfile.entitlements | 12 + macos/Runner/Info.plist | 32 + macos/Runner/MainFlutterWindow.swift | 15 + macos/Runner/Release.entitlements | 8 + macos/RunnerTests/RunnerTests.swift | 12 + pubspec.lock | 562 ++++++ pubspec.yaml | 59 +- test/widget_test.dart | 42 - web/favicon.png | Bin 0 -> 917 bytes web/icons/Icon-192.png | Bin 0 -> 5292 bytes web/icons/Icon-512.png | Bin 0 -> 8252 bytes web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes web/index.html | 38 + web/manifest.json | 35 + windows/.gitignore | 17 + windows/CMakeLists.txt | 108 ++ windows/flutter/CMakeLists.txt | 109 ++ .../flutter/generated_plugin_registrant.cc | 11 + windows/flutter/generated_plugin_registrant.h | 15 + windows/flutter/generated_plugins.cmake | 23 + windows/runner/CMakeLists.txt | 40 + windows/runner/Runner.rc | 121 ++ windows/runner/flutter_window.cpp | 71 + windows/runner/flutter_window.h | 33 + windows/runner/main.cpp | 43 + windows/runner/resource.h | 16 + windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes windows/runner/runner.exe.manifest | 14 + windows/runner/utils.cpp | 65 + windows/runner/utils.h | 19 + windows/runner/win32_window.cpp | 288 +++ windows/runner/win32_window.h | 102 + 285 files changed, 17281 insertions(+), 38071 deletions(-) create mode 100644 FIREBASE_SETUP.md delete mode 100644 REFACTORING_PLAN.md create mode 100644 analysis_options.yaml delete mode 100644 android/app/build.gradle create mode 100644 android/app/build.gradle.kts delete mode 100644 android/build.gradle create mode 100644 android/build.gradle.kts delete mode 100644 android/settings.gradle create mode 100644 android/settings.gradle.kts delete mode 100644 android/settings_aar.gradle create mode 100644 assets/icon/icon.png delete mode 100644 assets/images/Icon_edit_color.svg delete mode 100644 assets/images/accounts.svg delete mode 100644 assets/images/accounts_color.svg delete mode 100644 assets/images/arrow_backward.svg delete mode 100644 assets/images/arrow_forward.svg delete mode 100644 assets/images/bg-image-blue.jpg delete mode 100644 assets/images/bg-image.png delete mode 100644 assets/images/cases.svg delete mode 100644 assets/images/change_password.svg delete mode 100644 assets/images/contacts.svg delete mode 100644 assets/images/dashboard_icon.svg delete mode 100644 assets/images/documents.svg delete mode 100644 assets/images/download_icon.svg delete mode 100644 assets/images/events.svg delete mode 100644 assets/images/filter.svg delete mode 100644 assets/images/flag.svg delete mode 100644 assets/images/google-icon.png delete mode 100644 assets/images/home.svg delete mode 100644 assets/images/icon_close.svg delete mode 100644 assets/images/icon_delete_color.svg delete mode 100644 assets/images/identification.svg delete mode 100644 assets/images/invoices.svg delete mode 100644 assets/images/leads.svg delete mode 100644 assets/images/logo.svg delete mode 100644 assets/images/logo_google.svg delete mode 100644 assets/images/logout.svg delete mode 100644 assets/images/menu.svg delete mode 100644 assets/images/more.svg delete mode 100644 assets/images/new_logo.png delete mode 100644 assets/images/opportunities.svg delete mode 100644 assets/images/opportunities_color.svg delete mode 100644 assets/images/pdf_icon.svg delete mode 100644 assets/images/search.svg delete mode 100644 assets/images/settings.svg delete mode 100644 assets/images/skype.png delete mode 100644 assets/images/tasks.svg delete mode 100644 assets/images/teams.svg delete mode 100644 assets/images/users.svg create mode 100644 devtools_options.yaml delete mode 100644 ios/Podfile delete mode 100644 ios/Podfile.lock create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png create mode 100644 ios/RunnerTests/RunnerTests.swift create mode 100644 lib/app.dart delete mode 100644 lib/bloc/account_bloc.dart delete mode 100644 lib/bloc/auth_bloc.dart delete mode 100644 lib/bloc/case_bloc.dart delete mode 100644 lib/bloc/contact_bloc.dart delete mode 100644 lib/bloc/dashboard_bloc.dart delete mode 100644 lib/bloc/document_bloc.dart delete mode 100644 lib/bloc/event_bloc.dart delete mode 100644 lib/bloc/lead_bloc.dart delete mode 100644 lib/bloc/opportunity_bloc.dart delete mode 100644 lib/bloc/setting_bloc.dart delete mode 100644 lib/bloc/task_bloc.dart delete mode 100644 lib/bloc/team_bloc.dart delete mode 100644 lib/bloc/user_bloc.dart delete mode 100644 lib/model/account.dart delete mode 100644 lib/model/case.dart delete mode 100644 lib/model/company.dart delete mode 100644 lib/model/contact.dart delete mode 100644 lib/model/document.dart delete mode 100644 lib/model/domain.dart delete mode 100644 lib/model/email.dart delete mode 100644 lib/model/events.dart delete mode 100644 lib/model/lead.dart delete mode 100644 lib/model/opportunities.dart delete mode 100644 lib/model/organization.dart delete mode 100644 lib/model/profile.dart delete mode 100644 lib/model/settings.dart delete mode 100644 lib/model/task.dart delete mode 100644 lib/model/team.dart delete mode 100644 lib/model/user.dart create mode 100644 lib/models/api_models.dart delete mode 100644 lib/responsive.dart create mode 100644 lib/screens/about_screen.dart create mode 100644 lib/screens/company_create_screen.dart create mode 100644 lib/screens/company_selection_screen.dart create mode 100644 lib/screens/contact_create_screen.dart create mode 100644 lib/screens/contact_detail_screen.dart create mode 100644 lib/screens/contacts_list_screen.dart create mode 100644 lib/screens/dashboard_screen.dart create mode 100644 lib/screens/help_support_screen.dart create mode 100644 lib/screens/lead_create_screen.dart create mode 100644 lib/screens/lead_detail_screen.dart create mode 100644 lib/screens/leads_list_screen.dart create mode 100644 lib/screens/login_screen.dart create mode 100644 lib/screens/task_create_screen.dart create mode 100644 lib/screens/task_detail_screen.dart create mode 100644 lib/screens/task_edit_screen.dart create mode 100644 lib/screens/tasks_list_screen.dart create mode 100644 lib/services/api_service.dart create mode 100644 lib/services/auth_service.dart create mode 100644 lib/services/contacts_service.dart delete mode 100644 lib/services/crm_services.dart create mode 100644 lib/services/dashboard_service.dart create mode 100644 lib/services/leads_service.dart delete mode 100644 lib/services/network_services.dart create mode 100644 lib/services/tasks_service.dart delete mode 100644 lib/ui/screens/accounts/account_create.dart delete mode 100644 lib/ui/screens/accounts/account_details.dart delete mode 100644 lib/ui/screens/accounts/accounts_list.dart delete mode 100644 lib/ui/screens/authentication/change_password.dart delete mode 100644 lib/ui/screens/authentication/companies_List.dart delete mode 100644 lib/ui/screens/authentication/forgot_password.dart delete mode 100644 lib/ui/screens/authentication/login.dart delete mode 100644 lib/ui/screens/authentication/profile.dart delete mode 100644 lib/ui/screens/authentication/register.dart delete mode 100644 lib/ui/screens/cases/case_create.dart delete mode 100644 lib/ui/screens/cases/case_details.dart delete mode 100644 lib/ui/screens/cases/cases_list.dart delete mode 100644 lib/ui/screens/contacts/contact_create.dart delete mode 100644 lib/ui/screens/contacts/contact_details.dart delete mode 100644 lib/ui/screens/contacts/contacts_list.dart delete mode 100644 lib/ui/screens/dashboard/dashboard.dart delete mode 100644 lib/ui/screens/documents/document_create.dart delete mode 100644 lib/ui/screens/documents/document_details.dart delete mode 100644 lib/ui/screens/documents/documents_list.dart delete mode 100644 lib/ui/screens/events/event_create.dart delete mode 100644 lib/ui/screens/events/event_details.dart delete mode 100644 lib/ui/screens/events/events_list.dart delete mode 100644 lib/ui/screens/http_excepion.dart delete mode 100644 lib/ui/screens/invoices/invoice_create.dart delete mode 100644 lib/ui/screens/invoices/invoice_details.dart delete mode 100644 lib/ui/screens/invoices/invoices_list.dart delete mode 100644 lib/ui/screens/leads/lead_create.dart delete mode 100644 lib/ui/screens/leads/lead_details.dart delete mode 100644 lib/ui/screens/leads/leads_list.dart delete mode 100644 lib/ui/screens/modern/authentication/login_screen.dart delete mode 100644 lib/ui/screens/modern/authentication/organization_selection_screen.dart delete mode 100644 lib/ui/screens/modern/dashboard_controller.dart delete mode 100644 lib/ui/screens/modern/dashboard_screen.dart delete mode 100644 lib/ui/screens/modern/dashboard_state.dart delete mode 100644 lib/ui/screens/more_options_screen.dart delete mode 100644 lib/ui/screens/opportunities/opportunitie_create.dart delete mode 100644 lib/ui/screens/opportunities/opportunitie_create.dart.bak delete mode 100644 lib/ui/screens/opportunities/opportunitie_details.dart delete mode 100644 lib/ui/screens/opportunities/opportunities_list.dart delete mode 100644 lib/ui/screens/settings/settings.dart delete mode 100644 lib/ui/screens/settings/settings_details.dart delete mode 100644 lib/ui/screens/settings/settings_userDetails.dart delete mode 100644 lib/ui/screens/tasks/task_create.dart delete mode 100644 lib/ui/screens/tasks/task_details.dart delete mode 100644 lib/ui/screens/tasks/tasks_list.dart delete mode 100644 lib/ui/screens/teams/team_create.dart delete mode 100644 lib/ui/screens/teams/team_details.dart delete mode 100644 lib/ui/screens/teams/teams_list.dart delete mode 100644 lib/ui/screens/users/user_create.dart delete mode 100644 lib/ui/screens/users/user_details.dart delete mode 100644 lib/ui/screens/users/users_list.dart delete mode 100644 lib/ui/widgets/bottom_navigation_bar.dart delete mode 100644 lib/ui/widgets/dashboard_count_card.dart delete mode 100644 lib/ui/widgets/loader.dart delete mode 100644 lib/ui/widgets/profile_pic_widget.dart delete mode 100644 lib/ui/widgets/recent_card_widget.dart delete mode 100644 lib/ui/widgets/tags_widget.dart delete mode 100644 lib/utils/utils.dart delete mode 100644 lib/utils/validations.dart create mode 100644 linux/.gitignore create mode 100644 linux/CMakeLists.txt create mode 100644 linux/flutter/CMakeLists.txt create mode 100644 linux/flutter/generated_plugin_registrant.cc create mode 100644 linux/flutter/generated_plugin_registrant.h create mode 100644 linux/flutter/generated_plugins.cmake create mode 100644 linux/runner/CMakeLists.txt create mode 100644 linux/runner/main.cc create mode 100644 linux/runner/my_application.cc create mode 100644 linux/runner/my_application.h create mode 100644 macos/.gitignore create mode 100644 macos/Flutter/Flutter-Debug.xcconfig create mode 100644 macos/Flutter/Flutter-Release.xcconfig create mode 100644 macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 macos/Runner.xcodeproj/project.pbxproj create mode 100644 macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 macos/Runner/AppDelegate.swift create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 macos/Runner/Base.lproj/MainMenu.xib create mode 100644 macos/Runner/Configs/AppInfo.xcconfig create mode 100644 macos/Runner/Configs/Debug.xcconfig create mode 100644 macos/Runner/Configs/Release.xcconfig create mode 100644 macos/Runner/Configs/Warnings.xcconfig create mode 100644 macos/Runner/DebugProfile.entitlements create mode 100644 macos/Runner/Info.plist create mode 100644 macos/Runner/MainFlutterWindow.swift create mode 100644 macos/Runner/Release.entitlements create mode 100644 macos/RunnerTests/RunnerTests.swift create mode 100644 pubspec.lock delete mode 100644 test/widget_test.dart create mode 100644 web/favicon.png create mode 100644 web/icons/Icon-192.png create mode 100644 web/icons/Icon-512.png create mode 100644 web/icons/Icon-maskable-192.png create mode 100644 web/icons/Icon-maskable-512.png create mode 100644 web/index.html create mode 100644 web/manifest.json create mode 100644 windows/.gitignore create mode 100644 windows/CMakeLists.txt create mode 100644 windows/flutter/CMakeLists.txt create mode 100644 windows/flutter/generated_plugin_registrant.cc create mode 100644 windows/flutter/generated_plugin_registrant.h create mode 100644 windows/flutter/generated_plugins.cmake create mode 100644 windows/runner/CMakeLists.txt create mode 100644 windows/runner/Runner.rc create mode 100644 windows/runner/flutter_window.cpp create mode 100644 windows/runner/flutter_window.h create mode 100644 windows/runner/main.cpp create mode 100644 windows/runner/resource.h create mode 100644 windows/runner/resources/app_icon.ico create mode 100644 windows/runner/runner.exe.manifest create mode 100644 windows/runner/utils.cpp create mode 100644 windows/runner/utils.h create mode 100644 windows/runner/win32_window.cpp create mode 100644 windows/runner/win32_window.h diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 768e734..d1437cb 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/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_ios-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_android-0.0.1+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_macos-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_linux-0.0.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_windows-0.0.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_analytics_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics_web-0.6.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core_web-3.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_web-0.0.2/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/ashwin/.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":"file_selector_linux","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_temp_fork","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"quill_native_bridge","dependencies":["quill_native_bridge_android","quill_native_bridge_web","quill_native_bridge_windows","quill_native_bridge_linux","quill_native_bridge_ios","quill_native_bridge_macos"]},{"name":"quill_native_bridge_android","dependencies":[]},{"name":"quill_native_bridge_ios","dependencies":[]},{"name":"quill_native_bridge_linux","dependencies":["file_selector_linux"]},{"name":"quill_native_bridge_macos","dependencies":[]},{"name":"quill_native_bridge_web","dependencies":[]},{"name":"quill_native_bridge_windows","dependencies":["file_selector_windows"]},{"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-07-30 21:23:30.262984","version":"3.32.8","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/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_ios-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.3/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_android-6.2.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_android-0.0.1+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_android-2.4.10/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"url_launcher_android","path":"/home/ashwin/.pub-cache/hosted/pub.dev/url_launcher_android-6.3.16/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_analytics","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics-12.0.0/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_macos-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"google_sign_in_ios","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.9.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_macos","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_macos-0.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"shared_preferences_foundation","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_macos-3.2.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_linux-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_linux","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_linux-0.0.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false},{"name":"shared_preferences_linux","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.1/","native_build":true,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"file_selector_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core-4.0.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_windows-1.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_windows","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_windows-0.0.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false},{"name":"shared_preferences_windows","path":"/home/ashwin/.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/ashwin/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.4/","native_build":true,"dependencies":[],"dev_dependency":false}],"web":[{"name":"connectivity_plus","path":"/home/ashwin/.pub-cache/hosted/pub.dev/connectivity_plus-6.1.4/","dependencies":[],"dev_dependency":false},{"name":"file_picker","path":"/home/ashwin/.pub-cache/hosted/pub.dev/file_picker-10.2.0/","dependencies":[],"dev_dependency":false},{"name":"firebase_analytics_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_analytics_web-0.6.0/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"firebase_core_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/firebase_core_web-3.0.0/","dependencies":[],"dev_dependency":false},{"name":"flutter_keyboard_visibility_temp_fork","path":"/home/ashwin/.pub-cache/hosted/pub.dev/flutter_keyboard_visibility_temp_fork-0.1.5/","dependencies":[],"dev_dependency":false},{"name":"fluttertoast","path":"/home/ashwin/.pub-cache/hosted/pub.dev/fluttertoast-8.2.12/","dependencies":[],"dev_dependency":false},{"name":"google_sign_in_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.4+4/","dependencies":[],"dev_dependency":false},{"name":"quill_native_bridge_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/quill_native_bridge_web-0.0.2/","dependencies":[],"dev_dependency":false},{"name":"shared_preferences_web","path":"/home/ashwin/.pub-cache/hosted/pub.dev/shared_preferences_web-2.4.3/","dependencies":[],"dev_dependency":false},{"name":"url_launcher_web","path":"/home/ashwin/.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":"file_selector_linux","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_analytics","dependencies":["firebase_analytics_web","firebase_core"]},{"name":"firebase_analytics_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"flutter_keyboard_visibility_linux","dependencies":[]},{"name":"flutter_keyboard_visibility_macos","dependencies":[]},{"name":"flutter_keyboard_visibility_temp_fork","dependencies":["flutter_keyboard_visibility_linux","flutter_keyboard_visibility_macos","flutter_keyboard_visibility_windows"]},{"name":"flutter_keyboard_visibility_windows","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"quill_native_bridge","dependencies":["quill_native_bridge_android","quill_native_bridge_web","quill_native_bridge_windows","quill_native_bridge_linux","quill_native_bridge_ios","quill_native_bridge_macos"]},{"name":"quill_native_bridge_android","dependencies":[]},{"name":"quill_native_bridge_ios","dependencies":[]},{"name":"quill_native_bridge_linux","dependencies":["file_selector_linux"]},{"name":"quill_native_bridge_macos","dependencies":[]},{"name":"quill_native_bridge_web","dependencies":[]},{"name":"quill_native_bridge_windows","dependencies":["file_selector_windows"]},{"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-08-01 11:26:07.022719","version":"3.32.8","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1c09cfb..3b0930e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,12 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ +migrate_working_dir/ # IntelliJ related *.iml @@ -26,15 +29,9 @@ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -.packages .pub-cache/ .pub/ /build/ -pubspec.lock -.vscode - -# Web related -lib/generated_plugin_registrant.dart # Symbolication related app.*.symbols @@ -86,6 +83,10 @@ ios/.symlinks/ local.properties android/local.properties +# Claude AI Assistant +.claude/ +*.claude.json + # IDE & Editor .vscode/settings.json .vscode/launch.json diff --git a/CLAUDE.md b/CLAUDE.md index a54664e..f434879 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,162 +1,137 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -BottleCRM Mobile is a Flutter-based CRM application for startups and enterprises. The app follows a modular architecture with consistent patterns across CRM entities (Accounts, Contacts, Leads, Opportunities, Cases, Tasks, Events, Documents, Teams, Users, Invoices). - -## Build & Development Commands - -```bash -# Clean and prepare -flutter clean -flutter pub get - -# Build for release -flutter build appbundle # Android App Bundle for Play Store -flutter build apk # Android APK - -# Development -flutter run # Run in debug mode -flutter test # Run tests -``` - -## Architecture Overview - -### State Management -- **Pattern**: Custom BLoC-like pattern with singleton instances -- **Location**: `lib/bloc/` directory -- **Key Blocs**: `authBloc`, `dashboardBloc`, and module-specific blocs -- **Access**: Global singleton instances (e.g., `AuthBloc().getInstance()`) - -### API Layer -- **Base Service**: `CrmService` in `lib/services/crm_services.dart` -- **Configuration**: Environment-based API URLs via `lib/config/api_config.dart` - - **Development**: `http://localhost:3001/` (debug builds) - - **Production**: `https://api.bottlecrm.io/` (release builds) -- **Authentication**: JWT token-based with SharedPreferences storage -- **Google OAuth**: Integrated with `google_sign_in` package -- **Multi-tenancy**: Organization header support - -### Navigation -- **Pattern**: Named routes defined in `main.dart` -- **Home Screen**: Login screen (no splash screen) -- **Bottom Navigation**: 5 tabs for main app sections - -### Module Structure -Each CRM module follows a consistent pattern: -``` -lib/ui/screens/{module}/ -├── {module}_list.dart # List/index view -├── {module}_create.dart # Create new entity -└── {module}_details.dart # View/edit entity -``` - -Available modules: accounts, contacts, leads, opportunities, cases, tasks, events, documents, teams, users, invoices - -### Responsive Design -- **Helper**: `lib/responsive.dart` -- **Breakpoints**: Mobile (<650px), Tablet (650-1100px), Desktop (>1100px) -- **Usage**: `Responsive.isMobile(context)`, `Responsive.isTablet(context)`, `Responsive.isDesktop(context)` - -## Key Files & Directories - -- **Entry Point**: `lib/main.dart` - Contains all route definitions and app configuration -- **Models**: `lib/model/` - Dart classes for CRM entities -- **Services**: `lib/services/` - API communication and network layer -- **Configuration**: `lib/config/` - API URLs and environment configuration -- **Widgets**: `lib/ui/widgets/` - Reusable UI components -- **Utils**: `lib/utils/` - Validation helpers and utilities -- **Assets**: `assets/images/` - SVG icons and images for each module - -## Development Patterns - -### Adding New Routes -Add routes to the `routes` map in `main.dart`: -```dart -'/new-screen': (context) => NewScreen(), -``` - -### Creating New Modules -1. Create model in `lib/model/` -2. Create bloc in `lib/bloc/` -3. Create screens following the pattern: `{module}_list.dart`, `{module}_create.dart`, `{module}_details.dart` -4. Add API methods to `CrmService` -5. Add routes in `main.dart` - -### API Integration -Extend `CrmService` class with new methods. Use the established pattern: -```dart -Future> getEntities() async { - // Implementation follows existing pattern -} -``` - -### UI Styling -- **Primary Color**: `#3E79F7` (blue) -- **Background**: `#ECEEF4` (light gray) -- **Custom Widgets**: Use existing widgets like `DashboardCountCard`, `RecentCardWidget` - -## Refactoring Plan - -**IMPORTANT**: This project is undergoing incremental refactoring/modernization. Before enhancing any screen: - -1. **Check REFACTORING_PLAN.md** for the current status of the screen -2. **If modernizing a screen**: - - Create new version in `lib/ui/screens/modern/` directory - - Follow the modern patterns established in completed screens - - Update the progress status in REFACTORING_PLAN.md - - Keep legacy version as backup until migration is complete - -**Current Status**: 9.4% complete (3/32 screens modernized) -- ✅ Authentication: Login, Organization Selection -- ✅ Dashboard: Modern responsive dashboard -- 🔄 Pending: All CRM modules (Accounts, Contacts, Leads, etc.) - -**Modern Folder Structure**: -``` -lib/ui/screens/modern/ -├── authentication/ # Modern auth screens -├── dashboard_screen.dart -└── shared/ # Common components -``` - -## Configuration Notes - -- **Firebase**: Integrated for analytics (configuration in `android/app/google-services.json`) -- **Android**: Min SDK 23, Target SDK 35 -- **iOS**: Deployment target 11.0 -- **Dependencies**: Key packages include `flutter_svg`, `http`, `shared_preferences`, `firebase_core`, `connectivity_plus`, `file_picker`, `flutter_quill`, `google_sign_in` - -## Google Sign-In Configuration - -### Android Setup -- **SHA-1 Fingerprint**: `67:C4:BE:5A:97:39:47:0B:40:2C:14:05:F1:81:AB:C7:E6:CF:A7:DF` -- **Package Name**: `io.bottlecrm` -- **Google Services**: Configured in `android/app/google-services.json` -- **OAuth Client**: Android client type with SHA-1 certificate hash - -### API Integration -- **Endpoint**: `/auth/google/` -- **Method**: POST with `idToken` parameter -- **Flow**: Google OAuth → ID Token → Backend verification → JWT token - -### Environment Configuration -Use `ApiConfig` class to manage different API URLs: -```dart -// Check current environment -ApiConfig.getCurrentEnvironment(); // "Development" or "Production" - -// Get current API URL -ApiConfig.getApiUrl(); - -// Override API URL (optional) -ApiConfig.setApiUrl('https://custom-api.com/api/'); -``` - -## Testing - -- **Location**: `test/` directory -- **Focus**: Authentication and validation testing -- **Command**: `flutter test` \ No newline at end of file +# BottleCRM - Claude Context + +## Project Overview +- **Name**: BottleCRM +- **Platform**: Flutter +- **Version**: 1.0.0+1 +- **Flutter SDK**: ^3.8.1 +- **Design System**: Material Design +- **Icons**: Material Icons +- **Architecture**: Modern Flutter best practices + +## Project Structure +- `/lib/` - Main Dart source code +- `/assets/` - Application assets (images, icons, fonts) +- `/android/` - Android-specific configuration +- `/ios/` - iOS-specific configuration +- `/web/` - Web platform configuration +- `/test/` - Unit and widget tests + +## Development Guidelines + +### Design & UI/UX +- Follow Material Design 3 principles +- Implement modern UI/UX best practices +- Maintain consistency across all screens +- Use responsive design for different screen sizes + +#### Card & List Styling Guidelines +- **Flat Design**: Use flat, minimal card styling similar to Asana/Jira +- **No Shadows**: Avoid Card elevation/shadows; use Container with borders instead +- **AppBar Styling**: Keep AppBars transparent/white (no backgroundColor: inversePrimary) +- **List Items**: Use bottom borders (Colors.grey.shade200) for item separation +- **Dashboard Cards**: White background with subtle grey borders and 8px border radius +- **Task Cards**: Add left border with priority color (3px width) for visual hierarchy +- **Consistent Spacing**: Use 4px vertical margins for list items, 16px horizontal margins + +#### Color Guidelines +- **Borders**: Use Colors.grey.shade200 for subtle separators +- **Priority Colors**: Green (low), Orange (medium), Red (high), Purple (urgent) +- **Status Colors**: Blue (new), Orange (contacted), Green (qualified), Red (lost) +- **Backgrounds**: White containers with minimal border styling + +### Code Standards +- Follow Dart/Flutter naming conventions +- Use descriptive variable and function names +- Implement proper error handling +- Write clean, maintainable code +- Add appropriate comments for complex logic + +### File & Folder Structure +- Organize files by feature/module +- Use proper naming conventions (snake_case for files) +- Keep related files grouped together +- Maintain clear separation of concerns + +### Dependencies +- **Core**: Flutter SDK, Cupertino Icons +- **Development**: Flutter Test, Flutter Lints, Flutter Launcher Icons +- **Linting**: Enabled via analysis_options.yaml + +## Common Commands +```bash +# Install dependencies +flutter pub get + +# Run the app +flutter run + +# Run tests +flutter test + +# Build for release +flutter build apk --release +flutter build ios --release + +# Generate icons +flutter pub run flutter_launcher_icons:main + +# Analyze code +flutter analyze + +# Format code +dart format . +``` + +## Key Features to Implement +- CRM functionality (contacts, leads, deals) +- User authentication and authorization +- Data synchronization +- Offline capability +- Modern dashboard with analytics +- Mobile-optimized user interface + +## Testing Strategy +- Unit tests for business logic +- Widget tests for UI components +- Integration tests for user flows +- Use flutter_test framework + +## API Architecture +- **Centralized URLs**: All API endpoints defined in `lib/config/api_config.dart` +- **HTTP Service**: Unified REST client in `lib/services/api_service.dart` +- **Authentication**: Google Sign-In + JWT tokens via `lib/services/auth_service.dart` +- **Models**: Type-safe API response models in `lib/models/api_models.dart` +- **Usage Examples**: See `lib/services/example_usage.dart` for implementation patterns + +### API Usage Pattern +```dart +// Get data from API +final response = await ApiService().get(ApiConfig.contacts); +if (response.success) { + final contacts = response.data!.map((json) => Contact.fromJson(json)).toList(); +} + +// Authentication check +if (AuthService().isLoggedIn) { + // Make authenticated requests +} +``` + +## Dependencies Added +- `http: ^1.1.0` - HTTP client for API calls +- `google_sign_in: ^6.1.5` - Google authentication +- `shared_preferences: ^2.2.2` - Local storage for tokens +- `jwt_decoder: ^2.0.1` - JWT token handling + +## Notes for AI Assistant +- Always use centralized API URLs from `ApiConfig` +- All REST requests must go through `ApiService` +- Handle authentication automatically via `AuthService` +- Use type-safe models for all API responses +- Follow Material Design guidelines +- Maintain consistent code style across the project +- Implement proper state management +- Consider mobile-first design principles +- Ensure accessibility compliance +- Use Flutter best practices for performance \ No newline at end of file diff --git a/FIREBASE_SETUP.md b/FIREBASE_SETUP.md new file mode 100644 index 0000000..951391d --- /dev/null +++ b/FIREBASE_SETUP.md @@ -0,0 +1,28 @@ +# Firebase Setup + +## Initial Setup for New Developers + +1. **Google Services Configuration**: + - Copy `android/app/google-services.json.template` to `android/app/google-services.json` + - Replace all placeholder values with your actual Firebase project configuration + - Get this file from the Firebase Console > Project Settings > General > Your apps + +2. **Required Configuration Files**: + - `android/app/google-services.json` - Firebase configuration for Android + - `ios/Runner/GoogleService-Info.plist` - Firebase configuration for iOS (if applicable) + +3. **Environment Variables** (if using): + - Create `.env` file in project root + - Add your API keys and configuration + +## Security Notes + +- Never commit sensitive files like: + - `google-services.json` + - `GoogleService-Info.plist` + - `.keystore` files + - `key.properties` + - Any files containing API keys or secrets + +- These files are in `.gitignore` for security reasons +- Use template files and environment variables for team development diff --git a/README.md b/README.md index 49d832a..2e7d540 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,561 @@ # BottleCRM Mobile -A Flutter-based mobile CRM application for startups and enterprises. This app provides comprehensive customer relationship management features including account management, lead tracking, opportunity pipeline, task management, and more. - -## Features - -- **Google Sign-In**: Secure OAuth-based authentication -- **Dashboard**: Overview of CRM metrics and recent activities -- **Accounts**: Customer account management -- **Contacts**: Contact information and communication history -- **Leads**: Lead tracking and conversion pipeline -- **Opportunities**: Sales opportunity management -- **Cases**: Customer support case tracking -- **Tasks**: Task management and assignments -- **Events**: Calendar and event scheduling -- **Documents**: File management and sharing -- **Teams**: Team collaboration tools -- **Users**: User management and permissions +
+ +![Flutter](https://img.shields.io/badge/Flutter-3.8.1+-02569B?style=for-the-badge&logo=flutter&logoColor=white) +![Dart](https://img.shields.io/badge/Dart-3.0.0+-0175C2?style=for-the-badge&logo=dart&logoColor=white) +![Android](https://img.shields.io/badge/Android-API%2031+-3DDC84?style=for-the-badge&logo=android&logoColor=white) +![iOS](https://img.shields.io/badge/iOS-11.0+-000000?style=for-the-badge&logo=ios&logoColor=white) +![License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge) + +[![Get it on Google Play](https://img.shields.io/badge/Get%20it%20on-Google%20Play-black?style=for-the-badge&logo=google-play&logoColor=white)](https://play.google.com/store/apps/details?id=io.bottlecrm) + +
+ +A modern, feature-rich Flutter CRM application for startups and enterprises. Built with a scalable architecture, BottleCRM Mobile provides comprehensive customer relationship management capabilities with multi-tenant support, real-time synchronization, and intuitive user experience. + +## 🚀 Overview + +BottleCRM Mobile is designed to streamline your sales and customer management processes with: +- **Multi-tenant Architecture**: Organization-based data isolation and role management +- **Offline-First Design**: Local caching with smart synchronization +- **Modern UI/UX**: Material Design 3 with adaptive layouts +- **Enterprise Security**: OAuth 2.0, JWT tokens, and secure API communication + +## ✨ Features + +### 🔐 Authentication & Security +- **Google OAuth 2.0**: Seamless single sign-on integration +- **JWT Authentication**: Secure token-based API communication +- **Multi-tenant Support**: Organization-based data isolation +- **Role-based Access**: Granular permissions and user management + +### 📊 Core CRM Modules +- **Dashboard**: Real-time metrics, KPIs, and activity feeds +- **Contacts**: Complete contact management with search and filtering +- **Leads**: Lead capture, qualification, and conversion tracking +- **Opportunities**: Sales pipeline management with stages +- **Tasks**: Task assignment, tracking, and deadline management +- **Accounts**: Customer account profiles and relationship history +- **Cases**: Customer support ticket management +- **Events**: Calendar integration and meeting scheduling +- **Documents**: File management with cloud storage +- **Teams**: Collaboration tools and team management - **Invoices**: Billing and invoice generation -## Requirements +### 🎨 User Experience +- **Material Design 3**: Modern, consistent UI patterns +- **Responsive Design**: Optimized for phones, tablets, and foldables +- **Dark/Light Theme**: System-aware theme switching +- **Offline Support**: Local data caching with smart sync +- **Pull-to-Refresh**: Intuitive data refresh patterns +- **Infinite Scrolling**: Smooth pagination for large datasets -- Flutter SDK 3.32.8 or later -- Dart SDK 3.0.0 or later -- Android SDK (API level 23+) -- iOS 11.0+ (for iOS builds) +## 📋 Requirements -## Getting Started +### System Requirements +- **Flutter SDK**: 3.8.1 or later +- **Dart SDK**: 3.0.0 or later +- **Android Studio/VS Code**: Latest stable version +- **Git**: For version control -### Installation +### Platform Support +- **Android**: API level 31+ (Android 12+) +- **iOS**: iOS 11.0+ (for iOS builds) +- **Web**: Modern browsers (Chrome, Firefox, Safari, Edge) +- **Desktop**: Windows, macOS, Linux (experimental) -1. Clone the repository: -```bash -git clone -cd bottlecrm_mobile -``` +### Development Tools +- **Android SDK**: For Android development +- **Xcode**: For iOS development (macOS only) +- **CocoaPods**: iOS dependency management -2. Install dependencies: -```bash -flutter pub get -``` +## 🚀 Getting Started + +### 📱 For End Users + +**Download the app directly from Google Play Store:** + +
+ +[![Get it on Google Play](https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png)](https://play.google.com/store/apps/details?id=io.bottlecrm) + +*Package ID: `io.bottlecrm`* -3. Configure Google Sign-In: - - Add your `google-services.json` to `android/app/` - - Configure Google Cloud Console with SHA-1 fingerprint - - Set up OAuth consent screen +
-### Development +### 👨‍💻 For Developers + +### Quick Start + +1. **Clone the repository**: + ```bash + git clone https://github.com/your-username/bottlecrm_mobile_v2.git + cd bottlecrm_mobile_v2 + ``` + +2. **Install Flutter dependencies**: + ```bash + flutter pub get + ``` + +3. **Set up Firebase & Google Sign-In**: + ```bash + # Copy template and configure + cp android/app/google-services.json.template android/app/google-services.json + # Edit the file with your Firebase project configuration + ``` + +4. **Run the application**: + ```bash + flutter run + ``` + +### 🔧 Detailed Setup + +#### Firebase Configuration +1. Create a new Firebase project at [Firebase Console](https://console.firebase.google.com) +2. Enable Google Sign-In authentication +3. Download `google-services.json` for Android +4. Download `GoogleService-Info.plist` for iOS (if building for iOS) +5. Place files in their respective directories: + - Android: `android/app/google-services.json` + - iOS: `ios/Runner/GoogleService-Info.plist` + +#### Google Cloud Console Setup +1. Navigate to [Google Cloud Console](https://console.cloud.google.com) +2. Create OAuth 2.0 Client ID for Android: + ```bash + # Get your SHA-1 fingerprint + cd android + ./gradlew signingReport + ``` +3. Add the SHA-1 fingerprint to your OAuth client +4. Configure OAuth consent screen + +#### Environment Configuration +The app automatically switches between environments: +- **Debug builds**: Uses development API (ngrok URL) +- **Release builds**: Uses production API (bottlecrm.io) + +You can modify URLs in `lib/config/api_config.dart` + +## 🛠 Development + +### Development Commands ```bash -# Run the app in debug mode +# Run the app with hot reload flutter run +# Run with specific device +flutter run -d + +# Run in debug mode with detailed logging +flutter run --debug --verbose + +# Format code +dart format . + +# Analyze code quality +flutter analyze --no-fatal-infos + # Run tests flutter test -# Analyze code -flutter analyze +# Generate code coverage +flutter test --coverage +``` + +### Code Quality & Standards + +This project follows strict coding standards: +- **Linting**: Uses `flutter_lints` for consistent code style +- **Architecture**: Singleton services with dependency injection +- **Error Handling**: Comprehensive try-catch with user-friendly messages +- **Naming**: Dart conventions (camelCase, PascalCase, snake_case) +- **Documentation**: Comprehensive inline documentation + +### Debugging + +```bash +# Connect to Android device over WiFi +adb connect :5555 + +# View logs +flutter logs + +# Launch DevTools +flutter pub global activate devtools +flutter pub global run devtools ``` -### Build +## 📦 Build & Deployment + +### Android Builds ```bash -# Clean previous builds +# Clean and prepare flutter clean flutter pub get -# Build for Android -flutter build appbundle # For Play Store -flutter build apk # For direct installation +# Debug build (uses development API) +flutter build apk --debug + +# Release build (uses production API) +flutter build apk --release + +# App Bundle for Play Store +flutter build appbundle --release + +# Install APK directly +flutter install build/app/outputs/flutter-apk/app-release.apk +``` + +### iOS Builds (macOS only) + +```bash +# Build for iOS +flutter build ios --release + +# Build for iOS Simulator +flutter build ios --debug --simulator +``` + +### Build Configurations + +The app uses different API endpoints based on build type: +- **Debug builds**: Development server (ngrok tunnel) +- **Release builds**: Production API (`https://api.bottlecrm.io`) + +Build configurations are managed in: +- `lib/config/api_config.dart` - API endpoint configuration +- `android/app/build.gradle.kts` - Android build settings +- `ios/Runner.xcodeproj` - iOS build settings + +## 🏗 Architecture + +BottleCRM Mobile follows a robust, scalable architecture designed for enterprise applications: + +### Core Architecture Patterns + +- **Singleton Services**: All services use the singleton pattern for consistent state management +- **Service-First Design**: Business logic is encapsulated in service classes +- **Repository Pattern**: Data access abstraction with caching layers +- **Multi-tenant Support**: Organization-based data isolation at the API level + +### Project Structure -# Build for iOS (macOS only) -flutter build ios +``` +lib/ +├── app.dart # Main app configuration & routing +├── main.dart # Application entry point +├── config/ +│ └── api_config.dart # Environment-aware API configuration +├── models/ +│ └── api_models.dart # Type-safe data models with JSON serialization +├── services/ # Business logic & API communication +│ ├── api_service.dart # HTTP client with auto-authentication +│ ├── auth_service.dart # Google OAuth & organization management +│ ├── contacts_service.dart +│ ├── dashboard_service.dart +│ ├── leads_service.dart +│ └── tasks_service.dart +└── screens/ # UI screens organized by feature + ├── dashboard_screen.dart + ├── login_screen.dart + ├── company_selection_screen.dart + └── ... ``` -## Architecture +### Key Architecture Components -The app follows a modular architecture with: +#### 1. Authentication Flow +``` +Login → Google OAuth → JWT Token → Organization Selection → Dashboard +``` + +#### 2. Service Pattern +```dart +class SomeService { + static final SomeService _instance = SomeService._internal(); + factory SomeService() => _instance; + SomeService._internal(); + + // Service methods... +} +``` -- **Custom BLoC Pattern**: State management using singleton BLoC instances -- **Modular Structure**: Consistent patterns across all CRM modules -- **Responsive Design**: Adaptive UI for mobile, tablet, and desktop -- **API Integration**: RESTful API communication with JWT authentication +#### 3. API Communication +- Centralized HTTP client with automatic JWT token injection +- Organization header (`X-Organization-ID`) for multi-tenant requests +- Automatic logout on 401 responses +- Comprehensive error handling with user-friendly messages -For detailed architecture information, see [CLAUDE.md](CLAUDE.md). +#### 4. State Management +- Service-based state management with singleton pattern +- Local caching using SharedPreferences +- Reactive UI updates with StatefulWidget patterns +- Navigation state preserved with IndexedStack -## Configuration +### Data Flow + +1. **Authentication**: Google OAuth → JWT storage → Organization selection +2. **API Requests**: Service → ApiService → HTTP → Backend API +3. **Data Processing**: JSON → Model classes → UI widgets +4. **Local Storage**: Critical data cached in SharedPreferences +5. **Error Handling**: Service level → UI feedback → User notification + +For detailed architectural guidelines, see [CLAUDE.md](CLAUDE.md) and [.github/copilot-instructions.md](.github/copilot-instructions.md). + +## ⚙️ Configuration ### API Configuration -The app uses environment-based API URLs: -- **Development**: `http://localhost:3001/` (debug builds) -- **Production**: `https://api.bottlecrm.io/` (release builds) -### Authentication -- **Google OAuth**: Primary authentication method -- **JWT Tokens**: Backend authentication after Google sign-in -- **Storage**: SharedPreferences for local token storage +The application uses environment-based API URLs configured in `lib/config/api_config.dart`: -### Google Sign-In Setup +```dart +// Development (debug builds) +static const String _developmentUrl = 'https://b2ad5166b831.ngrok-free.app'; -1. **Get SHA-1 fingerprint**: +// Production (release builds) +static const String _productionUrl = 'https://api.bottlecrm.io'; +``` + +**Environment Detection**: Automatic switching based on `kDebugMode` flag + +### Authentication Setup + +#### Google Sign-In Configuration + +1. **Firebase Console Setup**: + - Create Firebase project + - Enable Google Sign-In authentication provider + - Configure OAuth consent screen + +2. **Get Android SHA-1 fingerprint**: ```bash cd android ./gradlew signingReport ``` -2. **Google Cloud Console**: +3. **Google Cloud Console**: - Create OAuth 2.0 Client ID for Android + - Add SHA-1 fingerprint to OAuth client + - Download `google-services.json` + +4. **Firebase Configuration Files**: + ```bash + android/app/google-services.json # Android configuration + ios/Runner/GoogleService-Info.plist # iOS configuration (if applicable) + ``` + +#### Authentication Flow + +``` +1. User clicks "Sign in with Google" +2. Google OAuth flow → JWT token received +3. Token stored in SharedPreferences +4. User selects organization from available list +5. Organization ID added to all API requests via X-Organization-ID header +6. Dashboard and metadata loaded for selected organization +``` + +### Multi-tenancy Configuration + +- **Organization-based Data Isolation**: All API requests include organization context +- **Automatic Header Injection**: `ApiService` adds `X-Organization-ID` to requests +- **Organization Switching**: Clear cached data when switching organizations +- **Role-based Access**: Different permissions based on user role in organization + +### Storage Configuration + +- **JWT Tokens**: Stored securely in SharedPreferences +- **Organization Data**: Cached locally for offline access +- **Metadata Caching**: Lead statuses, sources, and other metadata cached per organization +- **Auto-cleanup**: Cached data cleared on logout and organization switch + +## 📚 Dependencies + +### Core Dependencies + +| Package | Version | Purpose | +|---------|---------|---------| +| `flutter` | SDK | Flutter framework | +| `cupertino_icons` | ^1.0.8 | iOS-style icons | +| `http` | ^1.1.0 | HTTP client for API requests | +| `google_sign_in` | ^7.1.1 | Google OAuth authentication | +| `shared_preferences` | ^2.2.2 | Local data persistence | +| `jwt_decoder` | ^2.0.1 | JWT token parsing | +| `font_awesome_flutter` | ^10.7.0 | FontAwesome icons | +| `intl` | ^0.19.0 | Internationalization support | +| `package_info_plus` | ^8.0.2 | App version and build info | + +### Development Dependencies + +| Package | Version | Purpose | +|---------|---------|---------| +| `flutter_test` | SDK | Testing framework | +| `flutter_lints` | ^6.0.0 | Dart linting rules | +| `flutter_launcher_icons` | ^0.14.4 | App icon generation | + +### Key Features by Dependency + +- **Authentication**: Google Sign-In with JWT token management +- **HTTP Communication**: Robust API client with error handling +- **Local Storage**: Secure token and metadata caching +- **UI Components**: Material Design with FontAwesome icons +- **Code Quality**: Comprehensive linting and formatting + +## 🧪 Testing + +### Test Structure +```bash +test/ +├── unit/ # Unit tests for services and models +├── widget/ # Widget tests for UI components +└── integration/ # End-to-end integration tests +``` + +### Running Tests +```bash +# Run all tests +flutter test + +# Run with coverage +flutter test --coverage + +# Run specific test file +flutter test test/unit/auth_service_test.dart +``` + +### Testing Guidelines +- **Unit Tests**: All service methods and model classes +- **Widget Tests**: Critical UI components and interactions +- **Integration Tests**: End-to-end user flows +- **Mocking**: Use mockito for external dependencies + +## 🚀 Performance Optimization + +### App Performance +- **Lazy Loading**: Screens and data loaded on demand +- **Image Optimization**: Compressed assets and caching +- **Memory Management**: Proper disposal of controllers and streams +- **Network Optimization**: Request batching and intelligent caching + +## 🔧 Troubleshooting + +### Common Issues + +#### Firebase/Google Sign-In Issues +```bash +# Problem: Google Sign-In not working +# Solution: Check SHA-1 fingerprint configuration +cd android && ./gradlew signingReport + +# Problem: google-services.json not found +# Solution: Ensure file is in correct location +ls android/app/google-services.json +``` + +#### Build Issues +```bash +# Problem: Build failures after dependency updates +# Solution: Clean and rebuild +flutter clean +flutter pub get +flutter run + +# Problem: Android build issues +# Solution: Verify Android SDK and NDK versions +flutter doctor -v +``` + +#### API Connection Issues +```bash +# Problem: API requests failing in debug mode +# Solution: Check ngrok tunnel status and update URL in api_config.dart + +# Problem: 401 Unauthorized errors +# Solution: Clear app data and re-authenticate +flutter clean +# Uninstall app from device and reinstall +``` + +### Development Tips + +1. **Hot Reload**: Use `r` in terminal for hot reload during development +2. **Hot Restart**: Use `R` for hot restart when changing app state +3. **DevTools**: Use Flutter DevTools for debugging and performance analysis +4. **Logging**: Check console output for detailed error information + +## 🤝 Contributing + +### Development Workflow + +1. **Fork the repository** +2. **Create a feature branch**: `git checkout -b feature/amazing-feature` +3. **Follow coding standards**: Use `dart format` and `flutter analyze` +4. **Write tests**: Ensure adequate test coverage +5. **Commit changes**: Use conventional commit messages +6. **Create Pull Request**: Provide detailed description + +### Code Style Guidelines + +- Follow Dart naming conventions +- Use meaningful variable and function names +- Add inline documentation for complex logic +- Implement proper error handling +- Write unit tests for new features + +### Commit Message Format +``` +type(scope): description + +feat(auth): add biometric authentication +fix(api): resolve null pointer exception +docs(readme): update installation instructions +``` + +## 📄 License + +``` +MIT License + +Copyright (c) 2024 BottleCRM + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + +## 🌟 Support + +- ** Documentation**: [CLAUDE.md](CLAUDE.md) for detailed architecture information +- **🐛 Issues**: [GitHub Issues](https://github.com/your-username/bottlecrm_mobile_v2/issues) for bug reports +- **💬 Discussions**: [GitHub Discussions](https://github.com/your-username/bottlecrm_mobile_v2/discussions) for questions +- **🔥 Firebase Setup**: [FIREBASE_SETUP.md](FIREBASE_SETUP.md) for Firebase configuration + +--- -3. **Firebase Console**: - - Enable Google Sign-In provider - - Download updated `google-services.json` +
-### Multi-tenancy -- Organization-based data isolation -- Organization header support in API requests +**BottleCRM Mobile** - Free CRM for startups and enterprises -## License +Made with ❤️ using Flutter -Free CRM for startups and enterprises. +
diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md deleted file mode 100644 index df9c6ad..0000000 --- a/REFACTORING_PLAN.md +++ /dev/null @@ -1,174 +0,0 @@ -# BottleCRM Mobile Refactoring Plan - -## Overview -This document tracks the incremental refactoring/modernization of BottleCRM Mobile screens and components. - -## Refactoring Strategy - -### Folder Structure -``` -lib/ui/screens/ -├── [original files] # Legacy screens in original locations -└── modern/ # Refactored screens - ├── authentication/ # Modern auth screens - ├── dashboard_screen.dart - └── shared/ # Common components -``` - -### Progress Tracking - -## 📱 Screens Status - -### ✅ Authentication Module -- [x] `login.dart` → `modern/authentication/login_screen.dart` - ✨ **MODERNIZED** (JWT token handling, improved UI) -- [x] `companies_List.dart` → `modern/authentication/organization_selection_screen.dart` - ✨ **ENHANCED** (Search functionality, gradient designs, staggered animations, improved responsive layouts) -- [ ] `register.dart` - 🔄 **PENDING** -- [ ] `forgot_password.dart` - 🔄 **PENDING** -- [ ] `change_password.dart` - 🔄 **PENDING** -- [ ] `profile.dart` - 🔄 **PENDING** - -### ✅ Dashboard Module -- [x] `dashboard.dart` → `modern/dashboard_screen.dart` - ✨ **MODERNIZED** (Responsive design, modern state management, enhanced UX) - -### 🔄 CRM Modules -#### Accounts -- [ ] `accounts_list.dart` - 🔄 **PENDING** -- [ ] `account_create.dart` - 🔄 **PENDING** -- [ ] `account_details.dart` - 🔄 **PENDING** - -#### Contacts -- [ ] `contacts_list.dart` - 🔄 **PENDING** -- [ ] `contact_create.dart` - 🔄 **PENDING** -- [ ] `contact_details.dart` - 🔄 **PENDING** - -#### Leads -- [ ] `leads_list.dart` - 🔄 **PENDING** -- [ ] `lead_create.dart` - 🔄 **PENDING** -- [ ] `lead_details.dart` - 🔄 **PENDING** - -#### Opportunities -- [ ] `opportunities_list.dart` - 🔄 **PENDING** -- [ ] `opportunitie_create.dart` - 🔄 **PENDING** -- [ ] `opportunitie_details.dart` - 🔄 **PENDING** - -#### Cases -- [ ] `cases_list.dart` - 🔄 **PENDING** -- [ ] `case_create.dart` - 🔄 **PENDING** -- [ ] `case_details.dart` - 🔄 **PENDING** - -#### Tasks -- [ ] `tasks_list.dart` - 🔄 **PENDING** -- [ ] `task_create.dart` - 🔄 **PENDING** -- [ ] `task_details.dart` - 🔄 **PENDING** - -#### Events -- [ ] `events_list.dart` - 🔄 **PENDING** -- [ ] `event_create.dart` - 🔄 **PENDING** -- [ ] `event_details.dart` - 🔄 **PENDING** - -#### Documents -- [ ] `documents_list.dart` - 🔄 **PENDING** -- [ ] `document_create.dart` - 🔄 **PENDING** -- [ ] `document_details.dart` - 🔄 **PENDING** - -#### Teams -- [ ] `teams_list.dart` - 🔄 **PENDING** -- [ ] `team_create.dart` - 🔄 **PENDING** -- [ ] `team_details.dart` - 🔄 **PENDING** - -#### Users -- [ ] `users_list.dart` - 🔄 **PENDING** -- [ ] `user_create.dart` - 🔄 **PENDING** -- [ ] `user_details.dart` - 🔄 **PENDING** - -#### Invoices -- [ ] `invoices_list.dart` - 🔄 **PENDING** -- [ ] `invoice_create.dart` - 🔄 **PENDING** -- [ ] `invoice_details.dart` - 🔄 **PENDING** - -#### Settings -- [ ] `settings.dart` - 🔄 **PENDING** -- [ ] `settings_details.dart` - 🔄 **PENDING** -- [ ] `settings_userDetails.dart` - 🔄 **PENDING** - -## 🎯 Modernization Goals - -### Technical Improvements -- [ ] **State Management**: Migrate from custom BLoC to modern state management (Riverpod/Bloc) -- [ ] **UI Framework**: Adopt modern Flutter widgets and Material 3 -- [ ] **Architecture**: Implement clean architecture patterns -- [ ] **Error Handling**: Standardize error handling across screens -- [ ] **Loading States**: Consistent loading and empty states -- [ ] **Responsive Design**: Enhanced responsive layouts -- [ ] **Accessibility**: Add accessibility features -- [ ] **Testing**: Add unit and widget tests - -### UI/UX Improvements -- [ ] **Design System**: Create consistent design tokens -- [ ] **Dark Mode**: Implement system-wide dark mode -- [ ] **Animations**: Add smooth transitions and micro-animations -- [ ] **Performance**: Optimize rendering and memory usage -- [ ] **Offline Support**: Add offline capabilities where applicable - -## 🔄 Routing Updates - -### Modern Routes (Active) -- `/login` → `LoginScreen()` (modern login) -- `/organization_selection` → `OrganizationSelectionScreen()` (modern org selection) -- `/dashboard` → `ModernDashboardScreen()` (modern dashboard) - -### Legacy Routes (Backup) -- `/login_legacy` → `Login()` (original login) -- `/companies_List` → `CompaniesList()` (original companies list) -- `/dashboard_legacy` → `Dashboard()` (original dashboard) - -## 📋 Migration Steps - -### Phase 1: Authentication & Core (✨ COMPLETED) -1. ✅ Login screen with JWT handling → **MOVED** to `modern/authentication/` -2. ✅ Organization selection with role display → **MOVED** to `modern/authentication/` -3. ✅ Profile model updates - -### Phase 2: Dashboard & Navigation (✅ COMPLETED) -1. ✅ Modern dashboard with cards and analytics → **MOVED** to `modern/dashboard_screen.dart` -2. 🔄 Bottom navigation improvements -3. 🔄 Side drawer/app bar enhancements - -### Phase 3: CRM Modules (📅 PLANNED) -1. 📅 Accounts module modernization -2. 📅 Contacts module modernization -3. 📅 Leads module modernization -4. 📅 Continue with remaining modules... - -## 🔧 Development Guidelines - -### File Naming Convention -- Legacy files: Keep original names in `legacy/` folder -- Modern files: Use descriptive names with `_screen.dart` suffix -- Shared components: Use `component_name.dart` in `shared/` - -### Code Standards -- Use null safety throughout -- Implement proper error handling -- Add documentation comments -- Follow Flutter best practices -- Use consistent coding style - -### Testing Strategy -- Unit tests for business logic -- Widget tests for UI components -- Integration tests for critical flows - -## 📊 Progress Metrics - -**Overall Progress**: 9.4% (3/32 screens completed) - -### By Module: -- Authentication: 33% (2/6) -- Dashboard: 100% (1/1) ✅ -- CRM Modules: 0% (0/25) - ---- - -*Last Updated: 2025-01-30* -*Next Review: After completing Phase 2* \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/android/.gitignore b/android/.gitignore index 0a741cb..be3943c 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -5,7 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties +**/*.keystore +**/*.jks diff --git a/android/app/build.gradle b/android/app/build.gradle deleted file mode 100644 index d3ea905..0000000 --- a/android/app/build.gradle +++ /dev/null @@ -1,70 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" - id "com.google.gms.google-services" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -android { - namespace "io.bottlecrm" - compileSdk 35 - - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - - kotlinOptions { - jvmTarget = '11' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "io.bottlecrm" - minSdkVersion 23 - targetSdkVersion 35 - multiDexEnabled true - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation platform('com.google.firebase:firebase-bom:33.7.0') - implementation 'com.google.firebase:firebase-analytics' -} diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts new file mode 100644 index 0000000..2177e21 --- /dev/null +++ b/android/app/build.gradle.kts @@ -0,0 +1,69 @@ +import java.util.Properties +import java.io.FileInputStream + +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") + id("com.google.gms.google-services") +} +dependencies { + // ... + implementation("com.google.android.material:material:1.12.0") + // ... +} + +val keystoreProperties = Properties() +val keystorePropertiesFile = rootProject.file("key.properties") +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(FileInputStream(keystorePropertiesFile)) +} + +android { + namespace = "io.bottlecrm" + compileSdk = flutter.compileSdkVersion + ndkVersion = "27.0.12077973" // Use latest available NDK + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "io.bottlecrm" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = 31 // Android 12 (API 31) + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + signingConfigs { + create("release") { + keyAlias = keystoreProperties["keyAlias"] as String + keyPassword = keystoreProperties["keyPassword"] as String + storeFile = keystoreProperties["storeFile"]?.let { file(it) } + storePassword = keystoreProperties["storePassword"] as String + } + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + // signingConfig = signingConfigs.getByName("debug") + signingConfig = signingConfigs.getByName("release") + } + } +} + +flutter { + source = "../.." +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 4278496..399f698 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0003f30..49ee323 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,18 +1,14 @@ - - - - + - + - - @@ -45,4 +32,15 @@ android:name="flutterEmbedding" android:value="2" /> - \ No newline at end of file + + + + + + + + diff --git a/android/app/src/main/kotlin/io/bottlecrm/MainActivity.kt b/android/app/src/main/kotlin/io/bottlecrm/MainActivity.kt index 8994983..56a504c 100644 --- a/android/app/src/main/kotlin/io/bottlecrm/MainActivity.kt +++ b/android/app/src/main/kotlin/io/bottlecrm/MainActivity.kt @@ -2,5 +2,4 @@ package io.bottlecrm import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { -} +class MainActivity : FlutterActivity() diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png index 0c1124c90a6c026f03db95b060aa1bd66ef19583..51cace046cc21ae50a2bf06e577af4e302122929 100644 GIT binary patch delta 3499 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 Hu0mjf;yl#w literal 2290 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 diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png index 3fbc6cae7d55db52bcb434dfd9634b55f9831915..45e4a7f47bedae5a45164e91274558c17e2e00ca 100644 GIT binary patch literal 14966 zcmV-+I*G-JP)kQ`KSP?S+o5m1yUK}Dh{Dk_4C3{enNbbc6z zQE`y@bqy$~B`UN)lbc4n`@OgSb?-TQ@2|e9eeUbCR`)yioE@raSAA7y$KF~SY!Ris zViXBM%GG~^zoq_;lX6+HO%PIT9p%Q9E~JFfNf=57^E`I^?z-w}kv}7+p>^Q<&=#P} zmM)Q)`hcdK8S03-$_RPAHd6INo}4zeMLIP1YD97dmw5Oc=t1Tu!0(nyqnD&KS#R8$ zqN6-s15QTq;9j*xJ(sXtQocw+R~OYq$`>SN1MA8rEK??|DXA*!#9c%=JJNNEHRPm( zJ*g;5Fgf&3*CLb>f<}+$&PWNPTNsuZnDn~5(l3F1|s?@P)?=oaj zb43)UWv8JtWh10&%vSUsR-b7@ zMWq8{ia~;hj!6k)G^nVQ&hZF_6n-Au$0~haM7@CO#-QO@BmG88c7SNCDdl3YRt34Ywmm7EMojI6dYN$wo)i)r?T@)2bOXx&s@lE3K)foS-cRuJ z6f+b-_7yOai$X|_juL2*8HzexSWqp^jn~18D&NXO>4_pYlK#|WX>?1`&#})i_v-R4 z+PxJQmLN+hxPuJsePGyU813Y2xR47$A=8h_knU4sv}$E)^HBt=2ySC){HJH81zJ@M zAQulFO_W{ZU9`N6Z`YSWjR1PqqCqz946led#S57>P`+s_F*pmNZB`6q2;O6U! zlINg&CrL znDh(;YRdKb%5h4iPiELVT^ImtMO7FnCMVCR719l8ET~~p)#gFxF{m6n6sX>Cbw+Ie z2#d#QBsX2+60I8)Mf?5rn;htK0?KYh~MP#dv%CLNTSTE=AC=+&rqqJe1!EU8fHbMOe}{`cn`^RGOAa ziBOcKBPxxrxm;bo34e@2)G(z(eyq*>&25ma?kd@9uuUrkGkl8aPVui2@AmkGukp+$ zce-gZ0MYf&}x$SNDXXhB9)5&;ila zAG$)#j3rW(KpjPdv=jMBiEYyFK8&7y!Pn)-KfR6eiHwf+TO4kDM35NRy8= zk}_3XmKAEy4WW>nmCjxsVtDUeIU1_8d|AxF$h#7rIK(jDy^>ZJ79@??uccNarOl}=Xz?h=(evSOHwli=Ak zYnFKpQM$qdc%J?Y^+`~M(*{T@>z)%tmxk|V#Oe3x2-58DpgY72v#rZ2VL+24>gEfo zQX(K%9aOU?<%yB#b7LA^tZsKSI;NouDQd{(8EmUmMdLLc4DxIg!3TnvWoN?`4!*ga zQEc_EFy)lH{VFnBw}>=mQ$waey_k*Aa+m^j}fOHE3 zn}*M>xWmSDP3Q*3ms+DLV?_CqCV!QpatFW0tSBX2J$yXoF@YyrMS|A2{MuJ=87N*&Yo`6?fqb<>>q1(CS`D8xkPt0D-dBMi`V!IyBUGdJGRywq-1{0hySGG$O|wZdD)z zgy?_E_h--vd;%H%Bzs&ElO3QqYOGlp`%N& zz&E(>JUIbMc7_PG&dV;h=a5R(r$?UtnWlk(*ldg#1F;uNJ-RXAV5Js94vowtFwe3b z;d=&6kAxK4Sfnb(YGcXL=4l1dfSQLamR_aArUs<6p2Bav$uz!)Y-E^T`S?6QkPNcy z@-C{cD3Y5)#0sqfq2a_lBI^+ZaY)cl1NI|%P+pnt*%0D=DWstaRLQ86$l4Dmh4Dx+ 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 AjsO4v literal 3459 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 Li_odL;}rEDVP#RC diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png index ab8c4846fda36bfe8496c2f350b22c34dfac5e77..0eea7473edf88d744894b8d1672c12675c74e7c3 100644 GIT binary patch literal 28411 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 H4ln-$x`A_# diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 449a9f9..573347a 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -3,16 +3,16 @@ - diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index d74aa35..a3fb32f 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -3,16 +3,17 @@ - + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 4278496..399f698 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,6 @@ - - diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index e9d7fb9..0000000 --- a/android/build.gradle +++ /dev/null @@ -1,50 +0,0 @@ -buildscript { - ext.kotlin_version = '2.1.0' - repositories { - google() - mavenCentral() - maven { url 'https://jitpack.io' } - } - - dependencies { - classpath 'com.android.tools.build:gradle:8.7.3' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.google.gms:google-services:4.4.2' - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -subprojects { - afterEvaluate { project -> - if (project.hasProperty("android")) { - project.android { - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - } - } - - project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { - kotlinOptions { - jvmTarget = '11' - } - } - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.layout.buildDirectory -} diff --git a/android/build.gradle.kts b/android/build.gradle.kts new file mode 100644 index 0000000..a58274b --- /dev/null +++ b/android/build.gradle.kts @@ -0,0 +1,31 @@ +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.google.gms:google-services:4.4.0") + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/android/gradle.properties b/android/gradle.properties index d582b46..f018a61 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,6 +1,3 @@ -org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=2g -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true -android.enableR8=true -android.nonTransitiveRClass=true -android.nonFinalResIds=false diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index db18181..ac3b479 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/android/settings.gradle b/android/settings.gradle deleted file mode 100644 index 433f611..0000000 --- a/android/settings.gradle +++ /dev/null @@ -1,26 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.3" apply false - id "org.jetbrains.kotlin.android" version "2.1.0" apply false - id "com.google.gms.google-services" version "4.4.2" apply false -} - -include ":app" diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts new file mode 100644 index 0000000..ab39a10 --- /dev/null +++ b/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle deleted file mode 100644 index e7b4def..0000000 --- a/android/settings_aar.gradle +++ /dev/null @@ -1 +0,0 @@ -include ':app' diff --git a/assets/icon/icon.png b/assets/icon/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fbac8d9dc620e4b4f9e5ae09e45d291f3bcfca6f GIT binary patch literal 250131 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

2Ky4=q2sPQ$t%$4xN2}CALo^QD;sPo>tiKd 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 - - diff --git a/assets/images/accounts.svg b/assets/images/accounts.svg deleted file mode 100644 index 3edb8d7..0000000 --- a/assets/images/accounts.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/images/accounts_color.svg b/assets/images/accounts_color.svg deleted file mode 100644 index 6a09e86..0000000 --- a/assets/images/accounts_color.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/images/arrow_backward.svg b/assets/images/arrow_backward.svg deleted file mode 100644 index 51a8bfa..0000000 --- a/assets/images/arrow_backward.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/arrow_forward.svg b/assets/images/arrow_forward.svg deleted file mode 100644 index 63b0df0..0000000 --- a/assets/images/arrow_forward.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/bg-image-blue.jpg b/assets/images/bg-image-blue.jpg deleted file mode 100644 index 2adb050ee2ecbd92b6a38f407fcefe32b145e35f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44377 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 M+l$z7)W6mL1BuXd)c^nh diff --git a/assets/images/bg-image.png b/assets/images/bg-image.png deleted file mode 100644 index 49d6742f77e1ea149811f42239fa31f55b0603cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 289333 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 z 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≠X^ojMaO3g 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 e!=+t(W$u6aEX@s)Y8-a}0000 - - diff --git a/assets/images/change_password.svg b/assets/images/change_password.svg deleted file mode 100644 index 9d503c6..0000000 --- a/assets/images/change_password.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/assets/images/contacts.svg b/assets/images/contacts.svg deleted file mode 100644 index b127ba7..0000000 --- a/assets/images/contacts.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/assets/images/dashboard_icon.svg b/assets/images/dashboard_icon.svg deleted file mode 100644 index 0873b39..0000000 --- a/assets/images/dashboard_icon.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/assets/images/documents.svg b/assets/images/documents.svg deleted file mode 100644 index 112df26..0000000 --- a/assets/images/documents.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/download_icon.svg b/assets/images/download_icon.svg deleted file mode 100644 index ef421c3..0000000 --- a/assets/images/download_icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/events.svg b/assets/images/events.svg deleted file mode 100644 index dfce83a..0000000 --- a/assets/images/events.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/filter.svg b/assets/images/filter.svg deleted file mode 100644 index 5de4314..0000000 --- a/assets/images/filter.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/images/flag.svg b/assets/images/flag.svg deleted file mode 100644 index 978b8cd..0000000 --- a/assets/images/flag.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/assets/images/google-icon.png b/assets/images/google-icon.png deleted file mode 100644 index 4bc4e1dd720056e0382fdbc646a1535db27efaa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6819 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 nn^SHT=x{~ - - - - diff --git a/assets/images/icon_close.svg b/assets/images/icon_close.svg deleted file mode 100644 index d2a188d..0000000 --- a/assets/images/icon_close.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/icon_delete_color.svg b/assets/images/icon_delete_color.svg deleted file mode 100644 index 598bbe9..0000000 --- a/assets/images/icon_delete_color.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/assets/images/identification.svg b/assets/images/identification.svg deleted file mode 100644 index 1cb79e8..0000000 --- a/assets/images/identification.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/assets/images/invoices.svg b/assets/images/invoices.svg deleted file mode 100644 index 43c13d4..0000000 --- a/assets/images/invoices.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/leads.svg b/assets/images/leads.svg deleted file mode 100644 index 10f6caa..0000000 --- a/assets/images/leads.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/assets/images/logo.svg b/assets/images/logo.svg deleted file mode 100644 index 515d279..0000000 --- a/assets/images/logo.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CRM - - - - diff --git a/assets/images/logo_google.svg b/assets/images/logo_google.svg deleted file mode 100644 index 2cc84b8..0000000 --- a/assets/images/logo_google.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/logout.svg b/assets/images/logout.svg deleted file mode 100644 index fb956bd..0000000 --- a/assets/images/logout.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/assets/images/menu.svg b/assets/images/menu.svg deleted file mode 100644 index b845e77..0000000 --- a/assets/images/menu.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/more.svg b/assets/images/more.svg deleted file mode 100644 index e6d6615..0000000 --- a/assets/images/more.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/assets/images/new_logo.png b/assets/images/new_logo.png deleted file mode 100644 index d3ee457cb5b5d2ce567ec28e3bec49968e321d72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14571 zcmeHu^BSO`crNJt1sN$k?0NC`_X zwS-D9vC<9S3;lea@AEf2kJm5PUa!|VbIzQZIq&zGnGOEup%Nt-BN+gIQbk!_696LU zClMe$3%xcy2lt^DiOYSJ$E48XOKScG0Cu1vfA6uU@yf*cDno^&leNl+J4ViqRVqmK zvezuGk?Q|6!3=vDzMgTC^J}G~VR60E)VNQ2fefG5{w9Qj6n`z8R7ilM>@|r6hKxjC z$oyXw_UJ94`gd9EJVJdXASCRBG{03uR$Bp~{H zKJU9?7m`L6z(}ZNWl6yUBIpf$5M5#iBzmr|-~JJVA;lqSNJSP&M1lmN-I0G(*ujl+ zzvZb(|3Lz3(>{hI?v5Z^{%g|KmC- z==!7iw-cxF`8yJSrxVHFHSsq){Y|ldae{>UFJk|{NIUww0$Hd=iq#f%L-?0@RS6jt z$;ELGbTcK}Y!yQ(LgU-yRT{ZEhz)pqVz0ltT;@CJVsoJr{fBQ=(XoTKyfp(20}?sY z3(6g(9C-E2nc0VA8C(2<&R!gA7IEC~l^JQks`QxiDf+eC_bPi#7L%py%^f|dtdN?i{Ya^XJ=pb4bf(V7YZ81R z;SyY`-maNE3aUJOk0uP3R5CLiXePKbLsS=)EBN0mD97@@89F1#PaE~{QU6tm#Y@2< znb8-DvNAO_FVS!tC~>F;M=Muc%c<~6e^ViLV7o!UnDB6Dju<8zs5QRvR}K~!j6Tc} z)l1{<5j1G54)1ZIwpN0=k@wNP`_A{5%7bwE!EVeoG~H32^`2ZI_BJ-hWz|}d&0sZg z;6gG-J+?zrz@d+(?a6|?hR`Ll7*x1V=Cx#jD4m**A++2r%K1+-vn~|5eirzk8CK)U z6~oaNQ;`_((cx~HC*FYun-lA*nps<+$-?o?aBlI&i8j-*4P7TC`CNMdN}orG?m@YE zxIm_=!d&{dL#?iP;hqf~okQ_>+zp@-$mZjXPpQMb~=! z9q$Q!u637Qpv{?)Pe44(6Ld+E?Xc(e_UGu6(#{v+zl-`Fbsm-EZsjtD?w`0`Q(0Lq zw}Y48v5iW*pUrDmM_tY%Mqt7ww1P)hN%fy}RB~t`&@@7G$AK z(s<7qy3o$s8PyX%r#06u1NX&?rr*c5{}f+e6k*htg$ty0O;l{zPp_bc;A)wTCI(`J zWHDAAIk~2M;F!tLe|Ne`p97zs`fYA7acKW0jeem*JpUu^oXzV37qD3h>W?yWL-G&; zXpgesAg<2ryeWT)8XTBoo+6jKrroMOG&T%ZQU!G;u^V=QUfG zy|S$}bY0K+!M)+n|5S)|?Hr86mgxOCu$bmV?MNnG&uU;D)vl7^mx4fz*+%U-70Ns@ z67z6B(0LVgHS!@6$O2`!nWp`OZK!<6`!kI;OG7#)H<_0P%tz~TUkG!6&*U#zK@~~l zv|5H6eK7N*vFye8;-aAf+8h}pV=2NgLi57wKv^EhJCFcwsWa848hA&2VtV@N2}%xu ziZ4*jnHliC?eS^g&Te23E4V{^+7b(0Fte9I&7ymL5uH9~uy1vRYd4krOQz>fymk8b zDxg{*jYwJ2s<6^ALE(#c6AUrpfWl_d^GF<%HezUcxh(U1Qy4X1Gduj&l?og(`9pTq zMs@|L!#q(#@h3V0zUZxw_akVOd8zjqz$#1`ZlZ~pC=Qk9e201S*-Ejw-c-kxuN?-rzf}YxBn<-Ysxhik);j7yp_4^*X|MF* zoOV2>v2sx%i$l`~rfF1r7|)E+}`2L8lq*)lnp==6ow9A|wUshyoD_KiW29@Ud*3+JtL$CwnWiQ9c2l(qwQ!|g0` zS4>v3i~7P2XLK9mdVCj|x^cHDhsZ%EeRnM1lLzkpT?E6;jd-eXvopxjjJGSll0zt@ zO!yLpwBsM2oqmOVzZ)MHQB<=+aG5*Ahzn7ky?*NFTgkmC*ROW76*0%^7bHDTZp!?q z^_-Pj-+fxW-HI!k`VRL1d2mG+_vtjRoz92=ui2MhWQ}1>RjWI#9<|r{co1(dgD(B| z0~*KAgxbjYz##EpaQtWNWd;Ln)+@$LGFtj3`ZubIZ`tidzqflmKZUwO@5zX;gLW5S z8LK4l^xcSqVfYOCm!q$#i_Z6Nc8>N}NPN!&)NzUkNkF|v!@GdB6H788uQOnvF-9if zAznm4jNl3NvG&-rdU+?L-rilKo)VTJtsiZDk?doR8+KlGi9e!M+fUca?bg!!S2;L~ zzOJqO($T9|PK}zzbT~+Fne1)}&pI27&BeLRzdN(OMKIFzxVa?=-d-STtiq2C=1y!- zfZ++(+PeAd0mO(FqTC7GaGCq4*4-m0KnpbEtjwpYK3e?R({%Gxx7hkM=ILaS;XKup z{7q1e;CHN1_VkDBKHX^61XKW$AQQS4MWnZA#5V?GoP9Ve{a{7VL1c2_>V-H> z4!HtVxg58(fw<53OlQ7^tTOj!bDX-}4Q&&Ttn)Abwo5;sFC2QZK;NxDwf~vtYSRud z-B0HsnejT?w81Q?#i&pdvwYIpca9o@KdTnsPGy1!SF8iS+fP8$;|51~aw{ff=VD81Mf z79f2%>Cvt*CDrLZ`~Wvg^YoURIg#WZE5K70iT;Dl!Ny^80`Wgp6?%dT*6dY&GSL~k za>^u01@3)sE+zp)$VB)r^6ov~xq;(3(T$%L8evlNGW!v9Q7RKgWk+b7c|&@}BvWJc z++lcSo$-aqlXP>!gh$8tPMyh1G4ce4&PPG4hd+1tAFM3JAkdTjHp7$KKeTR5WayP# z%pz{uYCL>jcl=B4-B#uHh{efIi?XM)8|&YjBf`A++DBnrTb zY2OpY<#CxD|6#FK*Kv2i>g4g*gKQ2Q>y7%_C&o7o!_y*j=LIJ0+Ym9tG*Hedo0()1 z5xg@OGpjv3@puR0waM`>T{Tt1lAic7_8^ChSd2W+OVHSB&0}UHE26?%Ke_3a#}AGI z1V-`6!xRn?_i^cgjg^blX9???Z6zfQ_oTh?Nke816+afnYJ9h4dI&<+q95u`8YYOE z^o-{owfu0y{#YOT_U%VtRil(%s)>-c5Tpdvru zZk^}q`K*Y(>gj@GzK{^!H=2&LG%=clczF|vI@eY1;{E<_E71NS70{QiPiot0IId3@ z^{p$MOlV1*Z_zmXzNSO|5doApC~6i@j7yld8vflQ6KnJA!A-v7Z%X`7F4Q1IjNI#f zo=W9kKC8^+s8fJo+-WVEb7_2zae}vrT_r(!ho8EQon8MmwmaIt@7(D1_$F)NA+7Y}5yvZBD+N0TJUE_Qev^WG{oW&d@6F1A{n-BKYWff24w4RPfbTZ595M9Q|;PGMlP1-RkIw)Fbj z>oa-f_lnRqf{ZLZ=*h6LwKam=1+axL{qacQBE>g5RlDi7>$B$WHb#3x#|oWRotX+L zzCrhfFB}lAwtVqZ&34SZ9X`Dq*&C1@45*(0WuFcGF^#gY2I0xM!P1rIk#jNDLub4; znI4WY(Ucp$@L&OklN8prKATZN2Cu3_9S6}{4+lO7qNf10x;5gc0`j>-x>w(W~h<(5Wo4n9{htQZbKK$Pb3&f6E7 zss6St91+-gQSuL?GMzvBu7ME}YTTKt7*9hIWQB>ZnPhk$s_ZZ`OMzE{?iQ)?CD=(Sipnafh!-X zT{VeI&jX&WL=%GwBh!JjmV8}iEnLpdgt^;BUiGG_Pksk_Qt;PgjSBsFF#1suw9i?V z(?eU#Aac8UrO?9?YFZ4=J|;wpAq6%KM?yWo)L-WFwvwmeyQ3S90&M;S+-#pNWtj1{Wb?6xdQs7Zo#8!+nCNE2>~mi&OgtEJC2F~ zoBK*>uqLTKQx_Qp%CQzIlF@hdH`@x1=wL9}m%y}~3sFM}V^2xJ7?U6YF%pB?8JkIJ z=bKi9HCe(?NAlJKI*13w(r0qTEhk~@>UrfyufMEK%Ek*P@@eh!zs?Ng6-%mSupyNVmspf!MI_{)Rj6k1+ykqk@{)4)<6 zJY4Lf3nCW1<#0GOH%0dj)~<7rNLCD zoCkYx@qk(ne5zh67Mmy&Fv!aNs1BapMy1ezeqVao_*WSBzIPR!1xi;2d`q>4o>}>v zwV5uFMYE{U@#?x)>8QjjuxyJh@1u|a_($Xu;B?@3vJW`5;Z<2_|F&U^fWOA z37BM>Zc?0caZjnKE?1e(DYH z`e6X#C#snNlxMKIEqpE;b`Y6~B;H0H51NQ1wo?Y7QDb-VMklka_7g2Xqx`l53YjPn zZP6cO#2lYVBjiB44&{Hxiv)RdzC)f)XbPG~P#Q9Qj+k zX>F;q<)>qf`G2KH7W}DjRwr!-4zN>im^E6(tRWg=Li5`jWb<$WCf5entnS)ZaWv?# zFEUwAhHe!3hv324KOQ3sKBcn!uvdbbANte$=cUeZQLm2K#<>O_6g&27N=eBnV_6O;_^%~vMN7Ix$jXtX{*5@uByL7Ge z4_elhiY~vLXIl1m&D~tNG>8j}3E7-VY)`f*jX{e!aD`u&VOvPwi!x+%3{;e(0=D=` zM|FdYhut+*zMly>1?9~j>unC0?NCPbVLz+5UfmylIreE{Z+Sq5hk*vb8>h+o==l=O_pAIzq z5RY3=Cf>HGILc&}uVOWzfCSk@)b!`-GDYRtVb%$E|(Ew`5V2b5#0 z?C-zY+dK@^NEf+UP%1Ia0TSI2a#Llw>2bRCYi7cWA(#fU6?hE|QPWvUA|zJLAtvnq zBwRYMT7AqhYL>uaKll2<=0IWzETixFZAPmhLIdx?YPp?U36Ahim~c3fL|Lg;9#{aS zM83&Q#3t|FM$fUw-on8#>feMm2^U!~5*r43pYexPLn-}FCWhQ+6Oz;omvRkAslIyA zXmIQ*7!i6tC(wjGV6mFDt&J)Gzur$r#1qmF*mQ#GeJ17Bh1qt;+tFhG_RTGyvw~`P z)7yJ^dwG!fW^(s{77&pGGk>7H>b11vFqR}w+sZ(r6=CtCZRLOo}L)TS{tC% zz^A*f8r&z4%f9UgjHP-f^_>vFSvF0ksW^8r84r9aF%dtpTAxrWX7rFet&@JpbASgg zuWdBEgOM&%Ad~na#@E!68nBNGR79dWffy7_4l5tF`^gGCD@kEmGHVWdB?HT8m-ZJg z2Sg8aH}rl(_bGj0msr5?~~)OX&3*n~azrxd`^m~XzArL2jvGUyX6fO1X7DeB8pnJlMGm432 z$7&*mWl~a3Y!7nt!>-pVqA|NZP{MTkZ_>-7z|ctZ-v1i6CdgCvZ+#?3mw69vd0Lwf0mZAm8}!0~P+S z2mr3cpWX%dPmg<{{Hs3tfD5-&pT%ngf$@fN=4r!H`b0>E1dN#zYE5HiuET)Iiv%eO zCl22^`?R5K=lc9f3C4$F2h?TAgHOpqDbQT{-v(y~Ovg0PVMIubK506UY;uc85mrxl zNQww49=>80wlyi+<#$z*+4bEevQ#m`O(;zwu~PY!G%(ZqzSFA@PRVWd-k@QMLWJ~M zw(k!+`X_!Xh*Q@@pKCyL<^Em)Tbjku6S9j({IhkCm868V$=k(^TMk|)9ac0zvq9M9 zEIaoIdCEmlRz13`@S824kDl#*wsF2!YE_4D&f4~(V;wN{QJ=^KrmYqS*d|L{AzWk5 z>wHrM!p?+1`IRIk#d1OceDVrnK|vgd`wEPmNiXD-cbo$o`P-R}X+yt~2&Hqe)$#rt z%i?b7K2s1SH>*EMb&NbRsjl6a;#77K<6OE6TG=shz7N$}{w~HuH`-KPWSSQmutJEh zP7qrE3>&gn1&& zc5A8ll}>_)VuU#6wrjcRWaY1at5-ir7DbqS>0+&2wLUVUM42Tritg()jNR!cN$N8z z@#~9H2RE!3-P23!6Te$+yilFHgDUN+KZzRDNX_<~vitUd1Zlr)Nc3mak>JKHjeg(f z=p?;jG{bd}*hz=0x4*uWe%oP?{vzp6Ayed(kxao43(5hV_)Z?w_tKe;%cq(DAX+FX zgW%TFAzP;l*Uk0JTlqQ?#RNKIaMsndJvbdA)8|w0d5) zYrpCTEuXLIK<`N2LOJwtW?q)?lj~-L%ev=;pX`hv*gQrpucH(oo?B<$@Nm-^xzs^0 z12@bnyq>>LdnF8GM?^9lO`Ih`Zi@Krn91`X^dB~w{o`}V)lk#PLN867)=y~)Z8Sf% zU0pyZrm-(QSP~YzJH?R{(Wzx<63B^7JzektH;&5d8G5CTz1nZ`Hs0YPlHJ$W09PzNaIhp~sk;4B zBus@r7aOlOZ?v0h5)z#qWk1ELBpgPTDmjD`3J+q_q20>Mt9qf?muP1g{dl-Yuw+Dq zuE%6z!E@zs2U@SP6MG1u^UMKVH2swd1WO;vLAqmt(SB_W9J5Ca`i~3Otz}KRL8A2N zBt_L)2{V+W8o8d61B1}K=U=gTg#~y9!ToNP0f~Upr)}LS^z}R6mUHi;C2f}ky(Q@` zlcf$Q>0VX&>5P*4HTk)vyo7acN0Pbbh%Tl^I3iO;iGM31N2m|`?H^5v?Dd7Ny~TnN zW1rtJWK~hEvLdL&`p%B}hRJPT!taO{v%P0E09T?)HO25uk(v`-`FeEU&+lk3- z(QUL99(Ac?NgcmtO?RXaArPPB(Ov29i*X%FfHH7Fpx<3$(|wE8gTyg-^{SL!z55Z* z)>WX_Xm33JNstJsnOX3Pt2hs(qJKQp$9a-aSGY7Ba5P9rR~P=mih<76sKG7Fy>e^j zx)bR#Y(+yiG9O4_5|X}XIX;KUMAm0 zHZ?D|zHS({Il5il2SklUKy zRL${@Sj0#U+hw1MG5|$45_iZAW)yLoug`-;weO;!?$;Y5&G4W2PZX3zDro{#?OT1g zgN8frm6rRdLhl;rot~GpBlc;*@4a_uO>(zi0$ucR1?^H#6CMXye7co!pw^7XFCI|& zN%lZm5#e_Y9{tgp{J*rUnL+GAHg#LGt&x|ka52TAzFlYYN%^jo2z{;$qYr!UZ%fuv zYPTF9PCzTjsHv~Kta-)GBhe5Iu$Gcc#z(Z>7z0w9`(Zf8J}^|F7&e?$_?zI&__Ts%pm z8zV!7$0h_FhdQgLzjb9V{~chjbUJYMsE5UKdD~HxCG`UP_uuh&CY5vC$NWcXd=)0U zWQ$@<5W3=NKgXcn_JNpmh6_4%`3FkdcF{42Ul>|2=0R3r2W~VX(!b`6E^Y3c&6d^< zqaDvMFc5M4nVH1UM5|DDtYRUSjee}dJNtQhNVvhwav*RK5T)E>KShCRl1Q8==bveU z;{(>ITygkb?iWWQ8V(WyEV8B|WdAuKGlzuU;ATGHt^(^K?uW1E3rjB4X{S~BD8#6U zOA)0QAwd&2a-4_dKRv+1*j2t2OnWZ83_O-}u$JIqkcd1>!%&suy)A zfk7MA)@}Do;Biu}SW;v&XRqs@(>CXK&qHOh@yN zdKz}{>^ysAhcftm{8On4ZVd0aX|A$8{74Yk>G922eC7&Z5hVAiK!4@@lOe@NPUI1` z{bEK}L4`UWoI&|I32;f330C7RA*8!09OyiUP7ICMcR??z^M{X{o5PxHHd)K^+hy^1 zh;;kSzv_Yd^V9h@>*0{;Nn!a|CDB`oz+iF`HbC)j+uPv=OU>cfC!E^LNq6#bbhIpX zeQVA|(+9C%;kq9?23mx+Tu~gIulKD4eLDKwJ!j+BXI}ISFWqZf4Pxz0a$V-+A1ltt zmhi6CQ+xEd!tGLrjzr&pyn>%G3nytZyEzlO#=bOl{;15~IRDS$VCb>74d3*Z_U6BMzIf(Y6X||j^nQH!X z>);Ayu1qr3;C@xU9EIS?Unj65GM2fGo8MAKLrgL2m=4hT6moaFQ z2=1h6l{lU>Jy}T*t%NhP1P;-DXK~2#-dc73nv(T&IOo;<`3ouKu_}fJj7#`9;^v%_ zC|-iEtqW_4Ss3T9kR8`=Q^T$g7V!&jCHYyL-j`=_8q4qr(RoMfZM`Y3GtB>@W6(Ab zQgcULZ9JC~n_Gd`j#}-P;8*15vwg(E`JOvCWb7rwMNRpXa-LMq&kEOF&^gys>EjX` zwW8v)Gh8nvaXtO=mhn6v$~qI%$h6nUdEzdo=XLe#TN1`cOvfAvG8kwO42^Q#EdI@m zk)hb^krGaT^OuKXKZFrMj1@>y?_M;=K|k8X z4g<2eu7@SosJLsl^||mjb1fAsbJXYhyk%X>6hoy_7G?sKe>OgoGvRbPW`+5{h>$tj zJ;fz5iX7tT46<`?qK!ECwu7S|=8(NwOYT*Pw(ir8@>E`$;S= - - - - - - - - - - - - - - diff --git a/assets/images/opportunities_color.svg b/assets/images/opportunities_color.svg deleted file mode 100644 index c54089b..0000000 --- a/assets/images/opportunities_color.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/assets/images/pdf_icon.svg b/assets/images/pdf_icon.svg deleted file mode 100644 index 8c9430a..0000000 --- a/assets/images/pdf_icon.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/images/search.svg b/assets/images/search.svg deleted file mode 100644 index 2497e94..0000000 --- a/assets/images/search.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/assets/images/settings.svg b/assets/images/settings.svg deleted file mode 100644 index de77c38..0000000 --- a/assets/images/settings.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/skype.png b/assets/images/skype.png deleted file mode 100644 index 6f6fecc109d6c5f2928d6c509bf0ff77b09ee6db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 917 zcmV;G18V$7uW}hCV0?T9lc;J2S{XhTbf6jT%InNC-Mr{irOyD|Pi7W6YzQp_35@Y=0grNUup(!AQFovfv zQHc2)yQ|-4V+7w~KR(6w7~@QD1u;gIh;=xOI0ya}Hes~p&v~7E`5Y#1`T^Xln(0mf z2-x*MByajlSlA^X;AU*=y=KXN!)MZ(AH#~u$1upm?8BNE>NvukjA27hb);~e~+QMspM22RDp_#qSXE;ir+>3A+3QiGawCIk8de6^_}Cqrv~P>O3weno@$iWVnIQ~69t~NHR$sK=p8(Uj|-S%cpA$(1WXj- zF0Vl^X8_N%PQd9QGxJf0fF*@mxUdG@odMj`BD<`b{*s6lt(cKQ%EUuDWnkk%L@E*RaJm8WFe{LowXSd`=vZOE*bLG1bhTU!tNmue* zCqInkF-CogXN!+qF^qaDP31ip%~ChrMF*w;b`qgW>Of(NCh r<|5pM>v2J~jMMl4Z^am2YxDdA`@ylUmZ>tV00000NkvXXu0mjf$BC;$ diff --git a/assets/images/tasks.svg b/assets/images/tasks.svg deleted file mode 100644 index 8b688ae..0000000 --- a/assets/images/tasks.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/assets/images/teams.svg b/assets/images/teams.svg deleted file mode 100644 index 47d7889..0000000 --- a/assets/images/teams.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/assets/images/users.svg b/assets/images/users.svg deleted file mode 100644 index 4b808c1..0000000 --- a/assets/images/users.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/ios/.gitignore b/ios/.gitignore index 151026b..7a7f987 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9367d48..7c56964 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 12.0 diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index ec97fc6..592ceee 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index c4855bf..592ceee 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile deleted file mode 100644 index 1e8c3c9..0000000 --- a/ios/Podfile +++ /dev/null @@ -1,41 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/ios/Podfile.lock b/ios/Podfile.lock deleted file mode 100644 index ba6961a..0000000 --- a/ios/Podfile.lock +++ /dev/null @@ -1,85 +0,0 @@ -PODS: - - connectivity (0.0.1): - - Flutter - - Reachability - - DKImagePickerController/Core (4.3.2): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.2) - - DKImagePickerController/PhotoGallery (4.3.2): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.2) - - DKPhotoGallery (0.0.17): - - DKPhotoGallery/Core (= 0.0.17) - - DKPhotoGallery/Model (= 0.0.17) - - DKPhotoGallery/Preview (= 0.0.17) - - DKPhotoGallery/Resource (= 0.0.17) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.17): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.17): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.17): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Flutter (1.0.0) - - Reachability (3.2) - - SDWebImage (5.10.4): - - SDWebImage/Core (= 5.10.4) - - SDWebImage/Core (5.10.4) - - shared_preferences (0.0.1): - - Flutter - - SwiftyGif (5.4.0) - -DEPENDENCIES: - - connectivity (from `.symlinks/plugins/connectivity/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - Flutter (from `Flutter`) - - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - -SPEC REPOS: - trunk: - - DKImagePickerController - - DKPhotoGallery - - Reachability - - SDWebImage - - SwiftyGif - -EXTERNAL SOURCES: - connectivity: - :path: ".symlinks/plugins/connectivity/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - Flutter: - :path: Flutter - shared_preferences: - :path: ".symlinks/plugins/shared_preferences/ios" - -SPEC CHECKSUMS: - connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 - DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d - DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c - Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 - SDWebImage: c666b97e1fa9c64b4909816a903322018f0a9c84 - shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d - SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7 - -PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c - -COCOAPODS: 1.10.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index cd3b7c1..019b0d2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,19 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 7A51D37E4B3C07A9E4AAB281 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E13FE53387896326A28CCC4C /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -32,10 +42,9 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3C58ADA2AF9A36231637C45A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 4A6BAEEE224906606BFF323C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 5991D44B20C96AC7C24A394E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -46,7 +55,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E13FE53387896326A28CCC4C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,22 +62,18 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7A51D37E4B3C07A9E4AAB281 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 8BE154EB6786E3C4EC629ADE /* Pods */ = { + 331C8082294A63A400263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( - 3C58ADA2AF9A36231637C45A /* Pods-Runner.debug.xcconfig */, - 4A6BAEEE224906606BFF323C /* Pods-Runner.release.xcconfig */, - 5991D44B20C96AC7C24A394E /* Pods-Runner.profile.xcconfig */, + 331C807B294A618700263BE5 /* RunnerTests.swift */, ); - name = Pods; - path = Pods; + path = RunnerTests; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { @@ -89,8 +93,7 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 8BE154EB6786E3C4EC629ADE /* Pods */, - D604E0DDD2E747A026FD7085 /* Frameworks */, + 331C8082294A63A400263BE5 /* RunnerTests */, ); sourceTree = ""; }; @@ -98,6 +101,7 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; @@ -117,29 +121,36 @@ path = Runner; sourceTree = ""; }; - D604E0DDD2E747A026FD7085 /* Frameworks */ = { - isa = PBXGroup; - children = ( - E13FE53387896326A28CCC4C /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 2BA59BFA6896C716E21F8987 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 07EEC1E0A643CCF1974E7732 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -156,9 +167,14 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; @@ -179,11 +195,19 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -198,51 +222,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 07EEC1E0A643CCF1974E7732 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 2BA59BFA6896C716E21F8987 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -253,6 +240,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -268,6 +256,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -279,6 +275,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -303,6 +307,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -332,6 +337,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -340,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -358,7 +364,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -367,10 +376,58 @@ }; name = Profile; }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -400,6 +457,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -414,7 +472,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -426,6 +484,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -455,6 +514,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -463,11 +523,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -482,7 +543,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -501,7 +565,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -513,6 +580,16 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..e3773d4 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + + + @@ -61,8 +73,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - - - diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4..6266644 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ -import UIKit import Flutter +import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fa..d0d98aa 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} +{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index b9c83c67ba6515a513125c9c806e9b32491b1a1d..54f7c8bf8a89ffb272b1b4bd285b801f5614e014 100644 GIT binary patch literal 480618 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

%H6i_vr7WtUn^0t;7D5XjNR3sK8vRM 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 literal 33004 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 Wzx$8Pwuk#6Qv0_4tul>AFaHnXr@!?8 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index bb03bf8191fa88bf8868a07491b7cacd7fb9366b..515c03121785c73921ecf91ca0714511b35da552 100644 GIT binary patch delta 527 zcmV+q0`UEd1Dynr8Gix*0008(idp~w0pv+UK~#90W06+TXFvifN(!!y)(i{`PoKTq zw0#c)UciFJ*V0f)hz_~;;4vd3BgvW>7#ObIyt8!W#+3MQ{5r8{mXZ|z`t=)zGDZf5 z{{%G0ga_oL#U*8x@$vGSn;6_Yw-2J{+qdrrkDO}lnfm(8TYv1D?X1m;a#Es_@-JPz z;o@L({?gU#qB@Y33=I5yyqU?-%jZq>3Q79)>lYTyzMd|#7p%B+^#+9d>({U6FJD2} z&tJSMsA$=;YPPq#N`#=fT0jwt4$roSKn=nu^l&{${A9jEurUf~U`2;^*T< z4se{B&tAA3k(h_p!u&uD%PDHLkV1hjMA+i7f delta 379 zcmV->0fhdY1d9WZ8Gi-<0051N9Sr~g0a8gsK~#7F?a@0+13?e~;MvV4CwZ7?;)w)H zu~dS+l_-damEdm>@-r+%OT|J2iI2u~cH$3+g^l71a)Ct1!yK2y^ODQ$j_Y;ND1s?0 zGQ|w+F5k@VGU#!zKG+BU0D3~|Ivb8}V7vLK#-bjF3nk$9`+sz!#{9C@UriPY26#E2 zJtdBj5>4xl+m8ADgp>{vLWAm9Jh8U22)X<-tS&FW_02sj&CSC8NgAR<5!l{4Ova}t zl9ThJ!qUxLK2z4T%j_9%ly^Ho#sZ)ys&s=836DV3M0m3VAP&HjR)m?U1XQYqdjc9FF*}VM)bC-oJvyGhp Zg6|P^lh%7c62<@k002ovPDHLkV1mRDuu1>` diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 4884bd88e1006d140462f07931ec0a3a86a4e8d4..a2efca6e0976481918c4919785168df7c1a958cf 100644 GIT binary patch delta 1282 zcmV+d1^xQ_28#-i8Gix*000A=FFF7K1ky=FK~#90rB{1UR8<)N&a%NG43j)oh{jeTR33mlz37bMH`Xd|*GhemQ!(xz8#}GwP6iH17 zk}^Wp4RGYKJa+eTn%%pPyLZpIdoO-}?BhIszwdd@cjVE}B!7VqL8L+KYnPB<404}~ zYRXG8(${cD_8&ancv$~9#0ZHXUif54 z`l41>M+>qXyifua3ILdyHPfK60IglRx^DoWu+W7eA;Dwg6C?zZtC65Z$TshzRIFCU zo{AW;IG!HGcExGsM1{uODX%++l@-flG2pSW34e#Vo@;E1i@A@5gv5#v+O~Bg0GvGC zhA9R(k4%c<^ANe8yrS%#RV$MwCr$MYhlEzr6c>o2IyoV4a}IA1Aru}Sx-KJaY0TnT zv!$@K^1gvu#DZrvK^w*#>pEGzO`sD~U5$?GPkh$!HEmj*l%OpwSoy5#V_liaG}Usdjkru& zRwG+sV&N+8{{2?Y*1`kzdtZ7XRi`aJ+uk`dGb4qVlyU6sk9^gD)oLx#)|_wEhlho} z_VU`Fn+eyHM2kh&-sryTZ47`?CQ>Em9KZgtA)5ERlU3 z2EcQ3bMAjmOo6kSf+VH0RmH~vz`)>;o6UtYk8+|NzdVVGRA#=CjsVVI>f)gy+5v*S z6m*Hm6W!nciBI-w0|NX91`X{Ot`HE!Jlc57$lg@DBM0u51OpBZ3QAq2F5dZ;Dt~?% zGskGEY8}m!XD!Sp#u%WuFu$lEkGMc4liAB0O_)r@W!2|8F1xAh+^#HHxS#t zkB&a-z5BQ1S0i?GYwRb1czDFt)qAQ|#MM-mS}azlt~SmjRlKvJFz`|ay8}rul=Hr1 z!%QH)c%{4N=AC4f?LFed2=6#ini*FWVN7rK7>3!DSG4){^-n()i4Xzl*6lt~O1Nf_ s*Kb-KPnt|$e0hY5Bp{R`;SXc@A7xL~)=Q6cH~;_u07*qoM6N<$f-MYh5dZ)H delta 879 zcmV-#1CacS3i}3-8Gi-<004~sxNQIc142neK~#7F?Uh?d6j2z*|1*1YFXr96p;019 z7Iv|+@S%s^f_w=KvIq(i3him>20?}Nkn|Kt;zL3=BD+#V=|d5|lu+I?%{6n`Ro7i- z*V&z!b2__*c#B<|AcOfW!<=)zGvEC7JIl9vtZ?-IS|A#lpnqC4LA7XtYS9GMq6w-+ z6I6>PsFo!KjhTh-IiqrP&PC=rc5y7O zr;6-Rgs}$2=W1YUBfX-5_vgUpzQNyzyY4; zkiRAu{ofpLkAHixIxPijb92x)FobcVxkMMAev0@#4-zubA$o+afNQFc5~BRE;6hf} ztayF@CK_%xqxyIynjSnw?U`!S)!)L6+VePCa{NJ&n_sLKt<$mo*!bOzqE zDm!6Q_`+5|@H#L#JPmnr^dg8n9aYd|N}D%Vh#ARAscbzR>8ZK!34XQ)Bqd~^?PD)O zvK1Dy6@Sey-r`<;9jo*+)EqmoD38dV!?=I3FmGdfZ4kj3*fhFe_%}b7wh!Gnakv}} z*X&rAmxViz-oR>!L+kr?G}hU1uzWAFGg8sh?_m4(!|C!MEhP~f3-i&@GdP=vQVEpM z*|{84CIW7uQ}pmM37L{uFtpGmrX!ZwF&;X38GrFMGsK_-Ns?KWo=0Lk_f5cP}YOi4tIK!a~C+!D04- zAgijyI~g=^Is>s&(cNt)A^(6d6iYc`5cGX*&Et)h0xAbb ziD(oUTx!n@%#GKF`(Ydx7UuO#muG!4a*RewWG_`hW6RfyBFL&Xrc4K8NX$ftB(i}R zQ6ds(lqZ(U|M^$9lF$Uzq6w-+6I6>Ps1{97Et;TOegd#KSa>f50rvm^002ovPDHLk FV1n@=q-6jA diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index fa4a85825acf7c8dac91f79760524003037eb64e..999e6e4f2a5a5a769557d54a78d3531a8cb7e0ce 100644 GIT binary patch literal 2388 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 delta 1351 zcma*n`9Bj1008jGlBUEqQbxi`pXN&RT*+8kh~<`=S9l2_UM%fxhGdSCC7c!GL6iI`GH=jzngAWYYQJ|WaD{@9h2MbxRrdu zWZsfh#{A{bDNdGDZPc-@N7?@Y3RsS4fQ-kYvCg$$^#oLCw+CW{rbR}CmkxmCp4|47 ztGa!qwg1F;kS0mgc z)#Sz^M^IiH?h<%??|y|2NQeBLwL<8>qq}a{ls}sgy?Bf7#qm^>UhTNmsCsiO^VAUd ztvb4U=|f_1RZnb(6^xsM(J~C~)17Dmx#Egtl-{vQ3BUyvTIp)d!*-3kt24{%Q=_kd z^iI)~;+1q@@9_(T>SkL668KPo-$1vdTdUuV*1HD6GTEdk97Ci~BI91L)TP)CKXgXBbbW^otbJ@eYHSEuB z@}~k2x&AKN#cA!wjq&mp@KtMvq5^WbOTde^a``Ggq<%-qyz>LzS^8GyHvFObZz+s1 zJh39+8W*Cko5)O!XC-gJHU<^ZEhFRcaxAqAKQ`vEjRFp~V6w zN?Q+^zVD}pJJx*IaU{5DMoh#Hrrd2VPVzCy>k`Wlbt4aBvZ_V*un7GPIm_UFXaW5xikiRI1zWJ?RNE2I|OB-i_snWT%Wv zpE&kd?Z3F92PmMjwCs@5{$a#rIfp7Nq%A1pMUTHH>zuNFzdg@mbK5}F;M(3ArY;bl zZCu_>bP@)m4qsgh73_20+?*`l?(_nATu#=<%Y zwKC2T6_#qt5sIssb#;MVUus#NyK9<{sVqP(KR&eSMAvrcz*z5?ABT(yde4+z?JL zW)Ns8-HU1DpIR38`~uZilNJe@v4nY`OwW2EPn9@!;?34%-{9d77JEJcEqm|F#nW4r zuI#n<*XQ(OqPWI*h5YB7cUW=M##w3k(ALRm^SPj()B^>3_e@p5kJxjfYq}^5@($Ce z`jyc8I@DArY*iHZv5f9hHn;N?;!XJmK>@S;hjFWypCXZTgk%6ZkYjB`FcHu@Ef66u ztIud19HveLyva3Lo7EV32gi!)h%dgYa@h z6>Yql42{xGkJ8a2(>uBG$c)UHk5GQIlJT57qwF5{bqR;8El(d7Ml$X*B6Z%lS7%ka xXT!nPaI30KhPMmImUYPo+qV%@`G4Zsm7)S9Tm0b=g@4Ngpi$Rs>yW;re*lxBrTYK? diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index c4fbdef06de96a4125f49ca119787be9d985e428..add7e42094d7f898f649d7dcee7f9fca893c935b 100644 GIT binary patch delta 828 zcmV-C1H=5w1jq)E8Gix*007zX@K^u<0}n|=K~#90W06+TXTS#3Rg^e6IUwwhpFZDz z_!z4)T!00aL|=Q2j+PpPy=(8`)VxaSn9IPxaOd8`8FQCb6lIcRB4Kl1zka)V!}gr? zI0i=Qnaj$`^6&qDDCa*eRV13Ls;r=*q;UG&B?y<3lS5ic0)H<1|KI=DZ{Pj?{RfYQ zSj=^@v+8NB`u^j`+(oM(jJ8QG}jFOXQE)X!6k%6(Xs^Hm+ zS3%L4pTB&8i+?|Q@^t=^)o40rFI>5L(Ub`twf3G7zkdJ5XRfS_l$@+o*Myl!hW-bI zA+}(=bMHZO*OdPD8hab_-TRN=GgnZ6kAZ>l&ASgMN^mE#-TMwRFfeGSDHAXk=0FVR z;V_z+nVErs@$cWi5PcA35Z&0)8Ja0L!hwN-!OzQufq&uuxrw1CjJIFfdq}8E#!Y43pb)0CXb zKY#upJC@jd{Qv)dWSt;m|1(^=dgJi1(<|0&{`&131FYPE2N}A#j9C25c;fW=)VwMJ z)h8p|MvQoS^Y;CJ28P7w5EBDkxEUfsg0~o81w8H~h+McbqQ%?O=P$Y@%*sxURZ~$! zcr}=T@$bKX4204(!lPgZpohcM*^8#mUWCs8db^s2FnDH8Gi-<0035#XAb}X0uo6?K~#7F?Uc`J6G0TmzcaI&G?k>GwxU?E zq9BMAse))h)RPAVh2p`3Hw&ILpdf;WLjQq?=N`0&9<-ohJm?|TgW?aUU{iXClC~tx zuGzM`n`E=Urjsan&Dn;fv_I(|mK?i->35%Sb@&2K z96N&dpTFQ+Zhr}PZ(PI3?NOXMK8QmH_v7-&Em?~7CVCF^CkBRh!!FyZnO~bV3i@m| zt#Vr{J@G9){Z}X<42(s7pGYYB_{DU?Qxo@bbl@;1re5Lo+mE<%={(kS6NTbRvxg8F zj%5kO(Hq?pJze)gCIYuyn`;TBRE8{fHFLFO;$GsqkbhBpQYv98mB!hjljz&E6Z6?c zWOEA63=KAW2z*$k*@!*c(<^E@<6F!poM>&!JC=L|&bgR?Y}g;4Of}YeZG7@&BX%p= z8*P61nXzDGDoQz1Td6LzdhZ6PYps5$Y2TB+@02`CpAk1V1mT3TPEnSHZd4qg^XCng zL@$@?aW=irHH**xH9$)!cdEInlDXM#^JZ-e{2T&k01co4^p~vz-s#R?)VWWR00000 LNkvXXu0mjfX7LcH diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 90aee90e254c81b23e8107d637c5a34af72c37d4..9db4e88d005ed0b167b55076c542b85dec19aa45 100644 GIT binary patch delta 2236 zcmV;t2t)Vz3B3`J8Gix*003^;-G2Z82!u&QK~#90y;^xxRYe$|c{~>$k6lD0HxLw4 zNlXoo<}o#w+%*?4?YN}Jlm%4QF^mG@R{xeqQ z^vyICpR2vX(;Ro z$JYbtTTR}FoWR}9+N(!5{G5NgKvE+Ua;s{&3u>Iv7k^#2GF{P&7r0oQ0RT0%bvb7) z2(3I5+6T1l-78E>QB6(F-NK^cl2R2`I}i&&SkEDNxVx=f9yMapk#lB5h!({RK{7soqT>7CWo0MtN&h47Hq{~q;Ocpx(9R)SH>~#aZH}GR`Ab(n zU$>Rk5q}YXaVS-``uX}yjTkp&(wP0}M^~-g^rXDpI96n2t91|U{Pnh2tBVB>ICA{^ zMax!ISJ$X}mXxZyp*x<*W2c<=rLrGYi#6x4<5 zpF_$~jb%DdpH^>ANn08<4*=A^?|&;CTtcOW5;J28S63H|qoT43LajKYolENo z`Z4?T(x|x*z>p3>^`wXT3+CY>M9Ke5CX*DhB#0C;Kq(_LF0i2RFFfAW)e51$2FdTz zJ~WpXid#hQJPfIaTV|$jHk)y?&1OTQ!Bj(#kh8Kq1I`PHJeJW_aTbJff1n|O?SIjr7PDVflP`*q-tm&stHFOsGT=yWe7Ur z@8|p0luUjVIEOXrZ_mVUl?VKue2^P{4#T)RQh#SRmWicD+wZe6=~>tc8; zI+2x~opV+z2_ZU)X_DP#5q4Lj?8W_t4;|1wtn1?CYfhdz!$^6>V~NJml7H}XcG2Y2 z>2tZ_kw$R_6DVPEb`EUUI-* zKdDh8bMt0iv!+dq-ITZzp}Q zTJ*WgPsZMHh+mQYf|8Q=&73v~LeRXK_lqIH6gNyr1En}bdCXoZDt|7ynVZ)!C=hWc z&Hn{1m-9JXth-ZC*dZvOK9^|bMd+j?z6RmyZh5}2;FxfHm3caadL$fI7;p`KThWWl zit2V<#`$=AVO*tUkCeqrk!E`NE}6fwO($eq>QH1rnl@?NDI^#V%FDmQ=&4g9GgJoR z>yM68VdStu&P|&@0DsCWD=%ODO{pCphk!mAfIM_EIyruc;^F2NwO}SL0;Z-P;VSY# z#wCIbdQpuq8k>v40mwe`x>~J?8`t>x`T$U0KHHd(EUF<(4x}c7VM1|IPF!kqAZGB1%xep zeR_t4y1H2*uNr-|D>d!VaVXr?LUA^t@PO%Srj&5V)L8hJTILbD@YTogUSZ+<-2@e~ zJO$>?kk4$kjR`wrHzrB^(8-^3V!llJ z^*Sr+N`tXyfPYLkMY&Q{cM;^5)8}&YZ!>I*KhxvK<-h0V<(#=#N+m0Cd`61FhI0m; z@)$Pify0@p2ageRDt5Lp-%Jn}5(P430Isk+sNlEKe28LDQiFX#gshQ4D483v@6{?Q zt1uISg92Xd-Gg^DN)iI@Vh{;#S8~BnVO+8F$8^cqoPS91NrY$Cz1rFHS8O(9GC>!M z^RC1=U8^XwdHE3o+l;+cfQ;tSPq9kJsxuT67H!?JXU_BpanG?YMai?0x(8HQnxrYI zf(*Zs-_^_+2+y}BCcdz+Xllf`R{nm_WKuH$5MSIzrma*HLfW(9rD_>uyKV&%CGSm7 z-kT0I!!-oixdHy~h4c~R>w)@Z5t$kzKoI$)83gs0P4Dur_J05>6jA~-BMoT)0000< KMNUMnLSTXe_BG-F delta 1264 zcmV=%QLf7u6cN zsMgR$wT3RLHFQy}p^It_T~ur6qFO^2)f&2}0vi^!gpW&l9V|Z^vcF3bt;dK*tRs*m z1~Afe4h$PXi-rS?pnSscLKu`hK)DCfSdItFg$L7xU|fb_zf@BY&0!-i!gv^|rOcTf%q8gR=|@L*FB0QTNS--EO|7eMhF_A@=XrM|(>kKz za=X!BZljZfGa07MEaIaRawNCobW8%8h~&BG?6Ea_Y=2_c4G~?ma2_hlKE%26jgVy- z#k+PO@H~&I!=I>~u>ar} z*pOE^Qa7Fc^Z7{A{8_1qNLn1Lj=s<7A9QqE8y%h2W@oRx-qB@marD^DUWeCDXWCsv z^8HRc&VLJ2E}Fk76BQ@FMb_4xYC}$x?uEI{qK-_x`66B`d>^^%Ucl;=%kj=fC1}5N z1&(16>8qYpMVF;6fz|F%Mfa6{K6a4cYolvSL-=JgqvHDkKk0i{Qe zBY*RTi8djyn=$IhV^ZN;1UkMP@d=dynVOay5q7OzP648;7 z$lrZLEyFMd^bNRB+t7+l>(|l|eURprQ>Rhzr&;8p$VPcxWi3EJrteL5P6NxD1|& zihnW;M;ktNk<&l^g6Gp7$I0p%h%PtIo%$HhzWk>05zaTYW9J8luxk0kSoy>wDF5m^ zHJ$D@I9O4Q-8(W-eYTd0+d{@6#7}=@a!64{fn`|`mYev9hT@I)O0aADIy9X*Km#$j z(EKYF%uPnh?MZZposI)Xzd=!XC9+>i!+$MdM%m>g=b#eM%Su9xEAj)#gJ+jYz`I?9-8%sv^+kxPJ`6qsP z>g=e_P%eef4p)w(r#_vfepB`R&&Yji-`GM#7Ttr+_5s&$v)DUqb`Ck4#7;+}Yk$z$ zMkF%cF#m&_?g;32+iF~WEjf}n_=Bx=>JAMdMP;AZI_ll;xh%P@Khb}di{Xt?bag4m zIs?NQj10>wN5P0dos4qqqf1YqM?MlAJRYjCn14A!(Yia`LzV*XkVP5ds~)lO2r26B zZ`n$JQpHpvfe^_idmQFTN92qwRcTeu!C`c>_R`H-=`0Yxr*G1AhhW^PD|?46^k$i| zh>}O9^HD_LQW&1Hx` at?>uTaNXqANzQHn0000q z36vDYwf=1HA_5ALV?_|TZw!b;L4puG00n{|DkAX$MUcD|AFdaN;w>ryF^J*~YIvwb z6hT)(pGP!;8xRz^HG&}bvMf7ONl$lG{i^!a-GkKQF*DUw^^f{@Rj+qSv(s6&amIiV zjp#>R)>9CD@_&ZD9D}AHVmLN7+3#8hX8;7ooH0*MAX#889W=}Wf=OU~=jbQ5I&*7a ze6yjU?^=i43(hzoBzV9DibIloaIz;mLoC+4Yv+C!^ok~c`zyla`yVeqe3)A7n8^!s z$u=0DAqk$@O-xD909rL~dijw4XsU}OxbKmfSuPl3jwuTS_MsL;v@BRJa!B$fp#`*Y zgGBIEC)^!@RxH_Isgl!p#V&zoaZ9a^6&DnUkPQL|2w;$X!Wm{(wA2ui0=UD$kI-la z`$E|}qlfcj#svU@sIc6SMTBR3Y#=ZR6yls6#TF}@L~sxULQeawyAOb4CktHdKJZLt z#0|Hs{ANwCBX><0J9uDU-4*HBgZ(2~UvzkGU3=fwE?)xD)c<|7k zeFuVP6%|Jm-aK~2c&K8P+~X0_6~<^pLMcVVvL=uWsX}x?+Z`A7F|>g;EK+b#Xkej= zG~y^!k`YYB5ez5Cff|!=1LFlgIhuBaiDOC+m^F%S0uS2Eam$ezNP{q*30Yvo;K^B_ zR>r}C7DNg<rX7W%Y5>b>Z@e(UFCGcBdD1~kvIgTB3 zQwl0^@VtD^Y+aCS4?B5?k)3N` zP=x#Nxgf2Cf@_1e)rz|Z<5`>~@i12NTo1IRP5jL9US6tKkFK&eoz868_9LDn)zeC9 zjWm!Xg6mwf?H$51p>;FxkDg@Bp{4Q4p#ux+)sgu^>FTv*W#uwt5pjal1WAl5y0s~^ zu>y-bZVGH0rMKS_JBG`*ZqcN8{7s_E2lLN&-#0K9EbzH8^pbvu%I(aW#&GxEy<4~a z^zFL!6-UxxU{0`r#7n_;;x0yd#I&fUah-F1Ue9ii-goD5RjSDTy?gh+w(xBOBr=@* zj$6lqN~=UZ%B2`6O9{fM9jVN$D*eyW4?bSF=)LW~>_Ws*oU=nCSD{FBQdJgCEu?;h ztyGpJg|>}&ZPSv+q>_e9aJHFId<4wbcBwS%SUR}g8aPB9XoXH*kSy*kqh2< z=dqd3{JdjllC9HhvAbDS7OIeFw+8hKpa1)#&6+d{^2IP_;_QKGvlhJd9#|Z(f(;o~ zXq(A75;Uqm-}5dTeDR39e{TB8g>`|+ ze415Ori&*&`0B#Nhy|wI1|KG7H(|=x->gBgAz}dv9vOo%x7=NJ=#ZElYCcf)5YNl2 zQN4Q8#;2a$rBjFYty7>0c>lh=^HOGGmx`v18;%({V$gsKv1#jfVbAp&H&2`K zOf=RJEr6O67x-CSI`!(&Rqiim?D3h;Oq)5EDpezPaG?vF1K7F{5etQrfx(7N+lp?V z`o^Lq(;t~!tL6#v@z_x#K3wtXzgMkEMuHhx1X)II8gb2)gQa={V~dx5=(B)`NwmmU zRzw`zEfXiq2s&C@{^`F44<9{$?vr(D*9r!uQZV_BqKhxR)J$rPM zE2T61o(G@QRh7;NI8ccdfwcXFC_}H`uzAF&qBmcilka&!PlvWG&+6RqvoBXVaENb$ z3-(S}yLNi}HU;^LYs*SjZ2M_Dijv6|%7Su%T>J~6aDA*j-Tuy3uU$WT?ki)iA1=Et z8E~QCf(<{C0ojJ)1svK_GuyOkj(;wBe?`J-fjPp4l6%2x*3&Oub@`wg)vE+`{oZ;fb4BPdRp^$i*`s&-6q0g^DiGl_MCAgb}aJaOO(D$+L@VNPV|K#Eh9J&ktN zXD(v@{C3?B!V~)tvZ*~T?lI%!o&p&LsGj4g(XAD6c;NE5QTefPHTDETBdJTNn=AIR z+RwfF_GQTrPoeVj^A%`ADD8w&&&v@PqK2j{{KX_*R;;vfs=f-uAd+X$iUXKHgpU{`EKI_%oLdylq&;7O2|;SJ^@S(C&?=9FfFtO;4ny#O>(9z|#?V#h3n!q5f6$g2%+ z+q#9YHGbRrt0fe9m%=8<-aH^Q!r6Rzmgg><7$0t{wG5YDCOnUDU?y)I*o)dfnlx(It4CLv zy{{@=y>r)YfK)UM3L$xq!my66D`4oki98Z$GK0`Ioy%QvusgYmF~;w?t0*s(lF~Kr zAB#X?9~v9WErZ%V=_#{c6&KWvoCJ6P(^OO^o9X=;65M(s6;-pvqyx%+Ndeq9>DF`3 zJ~ObiobjLjyM5uJB?eqhFhY+eB)MGFptG79Ih_s#bcU z>_pWn1rOa@+`r#>5Z1N*VH2l5R&k`#Tvb>{f(Cp@s63^pdlAmk!xTJ6lDR z+FQ{3(I(+jIX^Hsuje_%MK?BWe5#1sd{#XF%7P^yd<@v`8=$Oag{tIDKbi&6YU@bm z?6o)>amAqW@(TGoD8u2|$~yT58LCw~{?rEb&+gKxuwET0H-Rj?yY!>U_dlUKZG?jr zDG(?db|G1Ii>v?<`Wj6$SJG;Yzj>sCWyVAq46BhShvkdkD;YC>QaY1yuErxNLL%vD zol%WbPM?bK8~~9b#ZEyM&Keo`Th95Gtv}T~vBs`n_t0oWRde+_mofL6qHMK^vDFN( zOIFqrvCu{;FrYVFJ8bx6gQm@x^X!YSXB>wYX0Rw^ObZKQs;`8%H7~W|)j>jKdMOPI z*;e+ON7-^6vW&`PZpv7-YE|!=Ft&TwGe;NQeW0w&4zX;zAk#s-MIN2>Q}ju*OmGNq zI+&9sox$|mCqGnvsGK2UNTI+z`T5?7C)8+intwcVTB8OA=ySWDHGl5(E3O^4-@iJ7 z0(qBRz&?=&vY)_#|=REm9_iks3_2I8KUcGop$)+vaV$m{wCqJ_$kKketf`ms3@3wKK zYL?VQGtLAmNev&BAFjCm=Hi8~Jk`2ov*4mgl_~{O?kKuyWKj~gucFkP?!;S3P^93g zNe~3US>GW+C-jdoEIw3z__m1;zA^7o?;PM2m)PF=roYcvS00F}!*rLlv_YfTDp za_W<#wDOy8mzJzJzgKtRgyH<&J=TZTAs(NgC9TBc`0uEK9pP!!dd?DiZVlL+=jNZ^ ztGk49ZnrM85^w?An;c{Thk*>;Vo89f_|WR#W(=xC)McURSeAY9)vBGlcGo_sRsf?z z`!+n2hE!bLDMwkrQ9V;d%^WpC0G4d95(J&ij_Cw?oWWNsOE2u*BU_D!s>f9+EUdeI z$4(XRMZZIqlXaB)6n@702n}(ru5cVH`=F$2^OhgEDClv<>efDK`;MJT@}i3ZIo;wQ zlDlL+0uSe)B@OX!`o&|!vtIKsW2*S&`BxjX;x(s29C>pfAs1}FtqXQ!1TAJj_DZ0J zi&1eTPUoTu!b(8%^72qAn;ogF)L0BExeJoL@Qovp=X+?mh}4E#*_1&cbI;W?JxYh1 z1_AU-vP26xRL3`svaSiccI|eV5s>tw61s<$i)hlp*(p%Gx045mq(yb_G&*;UGC+QR z%jQkwkIHm<`;K3j!3Hx3kB^$jA}YovHg42Qphotj6XxFOgyk%#RkKFBwymU`u3h_m zI>TM&#xR+o9nqde)*cb*E>mykg%HSsoD16Prxt3?`v&OKvJ^uG^vz4<$pgzzKL3g^ zE>;ItHT{jD7<0`vSx7RLj4W&@v5|s%SoLaEM_qG;G~S%SJIg+d(gplRxL^lWgLX;; zT^NYLIJo$b!%Te@{S^YEEcSnkGpTr7?b^SS_oY^ruKrrT0qUX#hd&+{$*#KE1+FEy z<{-e-*a&?RWd-X*OWcZasIloF3>J*O?#dy9E|PC2rg>)K)W`iB2}ubw-#GQ*8Ad?D?e{6E zruzt+Xj4{$IELe3jG13_w6j9VWgQ+^pWZ#n%FE>+MiH?bsGx_!Coh$%U%%cNzi)R= z*Dl9ZDbNA%{RhiN-dvo09ShV0w~QM&3LoKMgK?IMUY(7g+yyIK;GuhqF$Cm#bkJti zAMLRIn)2TL2d=*H)(xAsnaLW82ryr@KsY#+;W{Fko6v%TWapR^J&0uyXFAcVaidpE zgVNP&Z@T5~&0Bu7WIzlS!LkA`mXr+gkO9}T0Ya9zs1ik#lI?(6LQ{*PBrJX*6iDNJ zgK*(sqJ2P-HauuHJN@&`z61|>EfN)Z-JFe;q9uN=l z7`Spm;|%Qr zNtJ;^#9DNWtB?p)N#~}F5`lO#Ainv3n(mg{r@p&M6y6M|CFs{`KKkzKjWDUq}1zilIv!kh#XijIz!3IQBfK$ zt54QKHRCC0A4)-T|GO+gydVYG>tWJNcQ5;6bj1ZL{LZP=z!7VxzY#|B7m0&h0|s!CHasYl$T2GtLK({GK}I<>=Conxpd5x7GEK`8<&=`MiXlm~9An9h zWf*#pF*(#sS}RjVvOT@m`xV~zkNdu_>;3}2Oiy=+thB1Mn3$NXi?bv2&-(r+z+Hbj z_AN6~ObkGEas1mmN&IWEOpN!0%5@P|P~f)1(O#Np6`TmsVj6YRXfYrEx9`q3OKr=S6&%srAjuI34NAIMwnSd<70 zJp14l&mI?JDl$jM2`Xr05st&{;8ghGwR@Av63dJxguS1Uwn5?U2WNqUhX`y1N}NAiC96cFX>L*uISm7XL-Rq!KOHOlqrYW9_F!*auMIz)}EjS}-^Ve2q*`EGqYdIF@^CXz8x*=RTqf2Vi+THq&QVnEY0Q8HFGs3tf5|yhCkjcf5-#)PMEZt>B5N&f|)Em7bi!HxYBo(_qDC( z&5&@6Z>U*_R|S^Iv##Ll6lo9$%IoY=?(~{}v)aSIOmh|?LxifXG2mt(^J-mm3v83( z`wfGQfCoMXvz6Ea-FuzL50QF-exTP~sz7_vahFfs&7o%Fljane)FOG30j+rqqyFG^ ztHM5V`(H~+EP1r%D_i}>CZdv0_gY9ZkBa3ZXGz_+N0yXcV6gsKEXKT#5!19XjbfRF2HTlD7Z%`eJ#zF_dVBXojquT>J9|tkDWEqBMN7ZEjB5 zLl|xHV}&VE!=5|(+_DpSC5shoWh_ZqFrJD8Z=9d|yGS_o8znbnAsXYJz>=yHlih#$ z9Y0;K6)+XfpG?*#n;G&-tYs(gG1I853?Ci;XA<@;1v=SH0gAZ*g^o3i&0-)fPNvG12}i0DeM*XP^AQ+(@}NZiM1?jzD(Bf3{Y2+U ztqjNbDfGOvD{i&2T6sbp!vUK7BJH|JIibW}{e=`gz8&7dR5?2NS_db4$YTia-z~IO zaxLE}*QxFko#gR$yEQ)#;X+4FAF-o}g@sWd9TrAH+LbBncfDtRuXg9FCHzjYO4jsG$OwZ%HK#Vl zqLY3+9`J;E1LwNKEDVA>rF^xwPp&W*ZyV09+3Dp?fetQgW%n**Ror4Lx?3|^LH|%_ z7XZjlg6RI*Yc^H_eo45n26mPjOMiB$>MCzV(ZV$MO(_b6zx1#qv!0ORw?2tg4qO}l z2}km>Qj+2r%)M0jfmSHtLv`NUZO&6cNdGuC))FkS>ss3}wFH>M#cmtp(B<70T$^B+4%8SPL_=rHl+*$@=CabU>mE`_e+P$gjJ{qTV|;FC&mhq@;ILDNA%`_f-^0B z!Ji|3v`+-I&?mptK&^@1^z~1XZkMMu8UdujjP!mVM7@x#^ZgEo^5!*>b)LUq8D&E6S&#AI2jN9e)vKC=o?fu9*5k$OsY~rxO6Frv= zr%^Y-K1Rsv-Htn=PMt_y%W)p{#Vnfz!ydWCLUsf!2e7(l=-Gt(aVHfStMBw|9^UP@uCB>mDT17T_|J=apafaJvi=N_ADb9MxFnRjJk70?78{WY=Z zxmGx6Qsb!H5_rZw?iy{77f0kM!MR5|EHVRnMhlwWHCu8U;Ee#X?y*h6Q|FACRa@yVTxjpj6zuyP^S^xk5 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 4884bd88e1006d140462f07931ec0a3a86a4e8d4..a2efca6e0976481918c4919785168df7c1a958cf 100644 GIT binary patch delta 1282 zcmV+d1^xQ_28#-i8Gix*000A=FFF7K1ky=FK~#90rB{1UR8<)N&a%NG43j)oh{jeTR33mlz37bMH`Xd|*GhemQ!(xz8#}GwP6iH17 zk}^Wp4RGYKJa+eTn%%pPyLZpIdoO-}?BhIszwdd@cjVE}B!7VqL8L+KYnPB<404}~ zYRXG8(${cD_8&ancv$~9#0ZHXUif54 z`l41>M+>qXyifua3ILdyHPfK60IglRx^DoWu+W7eA;Dwg6C?zZtC65Z$TshzRIFCU zo{AW;IG!HGcExGsM1{uODX%++l@-flG2pSW34e#Vo@;E1i@A@5gv5#v+O~Bg0GvGC zhA9R(k4%c<^ANe8yrS%#RV$MwCr$MYhlEzr6c>o2IyoV4a}IA1Aru}Sx-KJaY0TnT zv!$@K^1gvu#DZrvK^w*#>pEGzO`sD~U5$?GPkh$!HEmj*l%OpwSoy5#V_liaG}Usdjkru& zRwG+sV&N+8{{2?Y*1`kzdtZ7XRi`aJ+uk`dGb4qVlyU6sk9^gD)oLx#)|_wEhlho} z_VU`Fn+eyHM2kh&-sryTZ47`?CQ>Em9KZgtA)5ERlU3 z2EcQ3bMAjmOo6kSf+VH0RmH~vz`)>;o6UtYk8+|NzdVVGRA#=CjsVVI>f)gy+5v*S z6m*Hm6W!nciBI-w0|NX91`X{Ot`HE!Jlc57$lg@DBM0u51OpBZ3QAq2F5dZ;Dt~?% zGskGEY8}m!XD!Sp#u%WuFu$lEkGMc4liAB0O_)r@W!2|8F1xAh+^#HHxS#t zkB&a-z5BQ1S0i?GYwRb1czDFt)qAQ|#MM-mS}azlt~SmjRlKvJFz`|ay8}rul=Hr1 z!%QH)c%{4N=AC4f?LFed2=6#ini*FWVN7rK7>3!DSG4){^-n()i4Xzl*6lt~O1Nf_ s*Kb-KPnt|$e0hY5Bp{R`;SXc@A7xL~)=Q6cH~;_u07*qoM6N<$f-MYh5dZ)H delta 879 zcmV-#1CacS3i}3-8Gi-<004~sxNQIc142neK~#7F?Uh?d6j2z*|1*1YFXr96p;019 z7Iv|+@S%s^f_w=KvIq(i3him>20?}Nkn|Kt;zL3=BD+#V=|d5|lu+I?%{6n`Ro7i- z*V&z!b2__*c#B<|AcOfW!<=)zGvEC7JIl9vtZ?-IS|A#lpnqC4LA7XtYS9GMq6w-+ z6I6>PsFo!KjhTh-IiqrP&PC=rc5y7O zr;6-Rgs}$2=W1YUBfX-5_vgUpzQNyzyY4; zkiRAu{ofpLkAHixIxPijb92x)FobcVxkMMAev0@#4-zubA$o+afNQFc5~BRE;6hf} ztayF@CK_%xqxyIynjSnw?U`!S)!)L6+VePCa{NJ&n_sLKt<$mo*!bOzqE zDm!6Q_`+5|@H#L#JPmnr^dg8n9aYd|N}D%Vh#ARAscbzR>8ZK!34XQ)Bqd~^?PD)O zvK1Dy6@Sey-r`<;9jo*+)EqmoD38dV!?=I3FmGdfZ4kj3*fhFe_%}b7wh!Gnakv}} z*X&rAmxViz-oR>!L+kr?G}hU1uzWAFGg8sh?_m4(!|C!MEhP~f3-i&@GdP=vQVEpM z*|{84CIW7uQ}pmM37L{uFtpGmrX!ZwF&;X38GrFMGsK_-Ns?KWo=0Lk_f5cP}YOi4tIK!a~C+!D04- zAgijyI~g=^Is>s&(cNt)A^(6d6iYc`5cGX*&Et)h0xAbb ziD(oUTx!n@%#GKF`(Ydx7UuO#muG!4a*RewWG_`hW6RfyBFL&Xrc4K8NX$ftB(i}R zQ6ds(lqZ(U|M^$9lF$Uzq6w-+6I6>Ps1{97Et;TOegd#KSa>f50rvm^002ovPDHLk FV1n@=q-6jA diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 44d5c443402b4ea6d1811f2fd72c062c2a357e28..ee28bd08fe732959a185c27c83b8ed986462c365 100644 GIT binary patch literal 3902 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 M07*qoM6N<$g3Wn-3;+NC literal 1931 zcmcJQ`9Bj51IO|08*`*&d>eB_Ax%ODa~}Bg+?xf$!J?C3I*k$?-AQp%iRZ)0hywoty{Z;77*Vu?B5Zs025juA z8UB5QK7S*8H42AUCy?7zGb~_|T14A|>Kv!njNx8=@cU_ke3r4H$g;HxW;rx}c7DE; zwHXvoNz%K*kKPh1R{NPf!(yJqm&PI&qC+qPNgK66y=PE28M%K5XMr4^hc|QCL%KIR zLWfx~*m;ryR#!EabVg^>YRuzVng8&7#rA3olmiq>0JCsW!~O9o6v=*bNGoN{Z4=)6PHjfZdS- zJ5Fm3I%21_)z>Hg_Q{*gu<5Kp0fZWPI%7j1xhZG>N*s=T^8RFN^@z19*Y}9J`;lQ6lA!3m&Ywf| zb+>n1swp~#{E!SR9hV5iO9AdF=@><~IcYD2JqC++Jef(1=n2=nYJ`x~p2dGzjggoX zKH<`>01oieu0!^z>71$J6GZAggAPp+*k9{2%_!2G6goA`#NM7%R~>Kc&-HSX8Q=vqfWOJ9@W0`)WuP*x@;Ug16Om+E$O>{?Jqyu zOl2@Oj|{7oiKZ8=+v^!WPeLAxykcdV;W8&>r*R0@rKG#fqTRu}1&=pH^f zm#gZVQ*#^mA&_^AlY6VQ9diBTHNXrQV^RX>A&djAt-L{(2u|IRE5|N@Q*;HxcTgZ8 zL(Qaf*B(6*fwNcNok3tY%1nKErCT(zl#%)9g$=DRQCf_r5NKbcH1|=JQVcb|H;&9M zuGr3gnv-uixRlJX1{|LjqdmUVKd|VGB4k@u3MH-y)Z5CS#&wO7n)Y^{9d%GRXJJ~{(3OY>s>TPa> z{&|sUQJ91=6?GW-z8DJp9FibY-dM)BaW4?I=_O1&q6_Qixwrc6cs}!jcFVgIWTdE* zVN+r6uFf=E!RmHpDy5bLuzeslqATfsS{Kf5My~|6tV2<$=RkXF&Xk(-NaX2D$E6F< zp0<;VaR{2219}dt*VD=aY@atK24{kw0ov=g%5Y%mSR6$e*;cjRCG->D+7~7JWN5G8 zK_NLgiabXY6v>Tr;hnr%xM~(B0;}4}i;pp_4F;CDb@Aaq^s3Ufi6vFwzWsc{+?k(& zw@uRoP;9xpLs8nbeRBvtreZY59+anMKPVJzP~c^hb%(m$KBf9VnQ_nZbh7SsQ@{`7 zNjZ)|mm=e&A?7Cc8RFs1hvLaZ9%9pd=G>V^9F2Wj`|OkT8lFFVwa9llc6LXTL1VWT z|6n5BU#&W7C#}$2@cZZ(3uP7>!TGzpAog3B3kJ^8keE6J0Uhq#kEq~<`5n0s$+aOw zNCTAxqHa@MZXO`!Iwi6fxx6br@CADARnxtqb9>fw-zbyEL>2VRHjuZ#59y$FW8~e~ z@EGaoxi8iWtqcFfY6>4>+!UM687|5~e+&)7KAO|&egJ=IiK{b9KC1idEeZGwbVKdz z+B~jSkm*L-b^53B>5@X<0${jj0^3 zq8xC{Tn39 zine=A?_6QrsiE~2)>3Ldo4pfZevPLz-|mZApTDR5O|y)R_)6G7zhqT4Rx7mmHeyOZ zlC|#EQp*R7+K0qcD zN@AAJ5K})jOC*sPBC{AWzxUSnyXTy}_nP*-*LQxu<0B0S7u1}O}LI4UVhU^K^sAaBsO*A*9^3qZvloS|H>e4Y`BRd2gJYBcDAjb@hpLS$LQ^lgsL-&k69w)o6QL+dg{@10`(rG(t|m z^Dq7lx>AMl-6Cl@w)SLX7G(19Hs)g)N|B zf+VAV1sEQ?A}Q4;q#{XbLoPQWG7x39ohemrtHNW#WywnjjE;3FnG;4Y*$b%)^)Mub zAe45nOh$PGhCC|qF)o$3%#xClR1*j#RAW$lqFRNCZph>VRv-HAW0n7ZFYw%CeaUpS z@9dl>P>xbbRYN*V>1J6%!GPTC8|5H+iY3O-Bn9rHtS(FIxKJ5^Ey+eQ*;lUuLUA6s z1a>1)8a0X__J?D`m69iDW|ms(Wz{b9yoII&2SS$+#(~PnARvJy#lXyjjYiKA$ z$pm8f*KQUqUb14vD#91octHPZHSiA-*)4&PN-wm9>MI*^ByhKNQ5~%v2M5%E(M~M> z*Q%q*OZXaf5d=a2ZY7ajc+ur!@A=oGKD)!Nu9v4h)UVI_7zCf#^^lBfGhHvk{!nkE zIxlS^uhkYq`n0-l0BIznEul2kg0MDLH9-$T;2q>zqxQ2>saCTrB3fZGEedUzESq4s4hm7QD-m-j5MVPBU0*GvrAD?o=du?`d*Ie7B0-tOEHTb(^3p{s zZ%{O&4&CO{5bH=$+VoZ56BF@~+~?^6(tDEZn*Ia8WU;Za+{tC z)J(;);xe_Rqe}Zu=*oou{RIPP^^;TopQI0nnel@BEL4mcuyLVr8V03QiX4=rY@uqC zdL}-GQWYrF!D>X1`Lc)*eJ3Qu*)%&yTvBa_2@g1BrK>2>h<90Y5bgC0>I4cf2*QL^ zs=$*JK+;bQz%D`dthDgDEDu6TpPohU?2&9VhW)gpBNB?TcXQ@pz&{%2lIRl(jMR+l zq$3F?gg~R8;-iFN^n>1R81bBGjI+4U0$+l|+gL$2Or%5`2=6@`wHW%$D0oyyC#2|0 zrwl%YZUyz_=r1xHOS;hyeN5z1YCQ`yl}M~EP}2k{N`=9x-Bq)UdX~z|w465=LS)jG z+9t~;P5=)MLWEW11u{gZARY5qSt%uLIw@b0X7sIX z{rBE|SKe39g*a>WT-Am$Q88MgD|?eYYCbo^UhxXXFx`-P_9vwx zqjYRDWYB(J--}r3+N;-If9uoFmP4h&YQ%r!kCGz6E>;IwYD?*##=mK3!7)F1#`u96NT)!JGZ@hARhdypi+HW5_?@*1vxC z`AXAv6GKsx%8mMOxKaNNqrenhQK%OZMGgOo0)R#uidhDSYdSigf8pQ%xOd8wN1j}{ zdaWfp=)v>K z#?0%+Pb35hm=%@=#W<-K@X|Gh!aw(34fW*-vwTd->!a3|>fU?ow)Y;pE&ug7QyzJ8 z{H=d`YsM_k$|%d+0f?GPd)|`pI^#TlkU6fSSceq|hZJCT8of3fIN;CY#}3?NqtcHq z3oe`8(a|~Pyi3=t=}-nL{9yVdYHBWYjIZ8L=R*To^pCvzQul609QMuOha52Bw!dF> z&GmwgwNg3x_>ueXv*(Y_Jb(JEIWezP zyI%VwtdzIl;xQkj`4Gz}s~UiqB$sQ&?(*gBZoc;N-o4i^>E*b5(UPTS{o>-O&%6MV z&2a=mG*G^AC^^V}0y;58FD*ZZT#|C!eDJ3C-Z5d!xfeh1@KlmSP?+Shko2UDD<@}p znMeZ+P2z87it z@ei*tDzq}{8UsLEYirM*>kQg#(;hv#a~7~gJl(ssU3=9<9cP|D<*}zqXsN7@0jwG_ zC*iOVDnfA$1>9e4EiE@)dwJk8csIJJZ_*w2T>QKLUbSj9S?4GmhcaJWW#GxY`@V;- zzh#n(3p|jGQWKu}`44p1+0g;mxz(1N5BusahaLQlU3c06N_Ee8)l#iqclE_bAOGW* zUVcO2IEx7&!|Og>J?O2bvXY8e7g_>@?;mr-W&;Pr63WRzSp4y_Gk*5#sn5I!0G!LA z2sTs;M3FCV3<7~Q)lPK~Vif2SFb5qUNGc1gR;$ic-kJU0JMX?X@o)baw#$weoqzVw zA%neI&+Ey#*4mQYbnR~sICRvKk3V5tHbYWivWU-L#|A_k%~{x#6vvi#@7{jOi6a9x z3Vr&<+cSb&!w$&XK+cIThR zZ9Zrqtq~j?eBi!!{_}w+pMHU>7V5IsaZ1%1-_Y-QF}9AjXy+WsuZqK?M;z(_Ly!VE z@4_qQEm+jt;1Ck+Jvlb=Q09=Mf%wyGp}a^|Hg3ts%T74$oPXVQYme^jH1-VO&imQv zQ=cBCCV(ghlv-#A8Hhw1u5dHg4%-c_IoZ*I)vl+XeewP&kApO$|?Y)M{ux6M=r?Sk~F3ojx zZvTDv3Y8bByU<;B<#ik^*Db|4vLnRFc@;$7J@!Pqv&AYs%yX%K_=#u6-8}KfCw*UZ z;b|v-|DngGI;gPctnj+{&%C1QFu74LKVVnquw8Z%b-z7h)@yH0uT(M@mu&h3TF$8N zZCuh*KtKp(3NR~6rYKRCTKoZUS6_F_K?i(&@MfEoPHcYdu;+-B$y@$}_aUWZE6E<*UJDvjae@te5%{c)m3&RiVU5jLuli@3H{f2%>XIiaD)yMc09fZ(+L=0;j z2_Vx5kKU8X6GBqaToO(WuApj9d|PJ}YTO+e7v3%V^s`dHf|m#`tG4jGBsRm@W$Nq5 zNgv0`WCD`M0Hz>bmZX;ungzhMD5Y3XD!-7)hqEmVt2)sJ(8(~S?sC_WPqM^0v^+CZ zM83F(Ic3OEF$D-2Y@Z=e=Rsc@2LSl(W95Li@)F=7*<{(b+-1oPwdHl`9Ezt1=_W9e zN-N#1TQ?W>)t7?=x@wj%lqj1LO`5*^AatD935iY*2PUx?=Ru+pHKAD&_OhmUJWF>9 z(Zta+6kA!j8R5V~R!5Cj?cWCddIO`r_TRE)pGdX@1W&5d#!w^3#68BtAbR%M`}bDkcGD zfnXq~3Rn7?MJF~LIAEKtx9}LO6u4>6zvQ{BND!!*)I~*6Z^4nVj^={MWaem1p@#33$S>-!1lXxTq)Gqfb7g69)^S#+A3=T7C$WPwX>H zg2d=CYq$VWhEV;_h_*&Q9fd_{d@mO#AUOJQA!Q~-~;8+L8 zA^{!60IcRZ0$wf{>$%RCt{;18ON)=l`{dW%bekh6gi=mu6??9L5=Jddkjl*YeXK|W z$aEf>R>ti<^(e61c20v5YHq@DS66glF|Xp)rP`7e%anU44G|XI!^Q;WE0u2i!(|(7 z*w1U;Qp)DM_u+jHJ}Rn1aVHDW=^k z5Go*5N+|mSRZBcbGmj%NxSV%X*M;Yuwdd|TOQeVH!pp{XcGBIVtbt&!=wQ`}&22?` z6erO5MK6ZCMatsV6zDJtEb~+{3~LT&raJrrCyX7$GaAZ~K?@7t@)5S_CIfzX_Gt&~ z|FvQrqz^6CvfO>|9Wa_pW7vq@oZ^ zLB%9tz=1bb)MY#&)9Fx1)`tChoqqD@qemQ)Wko2>2MqGgojvFM3oaWA0+dDCEHzcf z>Tn#U;kzyU&5f9MX+S0FYpUnpi+-0Zj zzqZ$~w$>JkgM%Gfw0P-pC!O{A=PT5T5jND)G(b$l`4DojEy_){MYhawag?CK)Eff- z8D%2k=utuG@-q9n^AHg7kWhZ##=LfaOyep7cOC7fR94zp0M441R801 zp${|hDy{4lr)2jzVy3jN)NAGqsR<-7dG`*12~=5VN$zpAP=|*Gg+Y4mg_lSF=HSmCtM=KI))f>Rde#8?#^liz*CR0*1hXmmJ0b4>#**9*TQ$j7n2+jTjfC4J_na zl!@)#TF0Dz;=cRrapuo2n)BW~N<)1;Bwm8Gm9x0yYEru6s{UGOt}%;s$_ee}=Wu}x zB@#lTDh-f%^ClwpD=Qh3HXvfZp6gbtJd*6j|{#z1&e%&xcVUE!v2K}j&m9Ou=c3bbd^G@sZ=*|m@i`m=T+a_Fp<&Vxh?~x~-kpq>6 zwvl;&q^HsG@Jql!S=_FGr3>u9Nsu5SfHa81HMG&u5^hD6L-angVqvJyoIU5!snd)y zB~9vK{EMNB3)eTRz#hYPK7Qng{l30uAdnW(l2xz!{cnaJb<&&DXNiavRYgFCjfB{o zv_gWyNsct$uTUW=^vTPYuZUWS+BjgvI^T<6DHii!l=Rh% z>2=Nt&7M4czDz5M2ESlI?UHjmOM)=Na_Opz7-VI}thr-;dD+Cj+%@5bD>vxd+m~Jn z*^n&;U2?&gGtT)<1*i7IA? zj}Q6Y337OGSI}&n@K42&nN2ug@uET{0g!BPGC}+u;ZSkZ4*<%PddatdA}Z?52D>Rn z#S3`ljTt{Y{pYvc`1>rYQjcTD?T3DA|9z%B_7rPET18MlN0`orIy&hbaL5K!t5%}12HbwTZ8qAl-$x4;2O7NQAaxQ8{9 zv9z7(6q#rz5l+5E!<_f$-F@HW5r-cf3qhy=?zQ`_ciuCZmQ3t17p9~o(5j^ zsJd&k`LZMiD%EG7d-1#9IXJGJL$~QBn{;+|=3DrcQWhKl`95$y6Th1TdFpg)dJK$- zEBFI&lFKN(9V>8ZV+NZ(DXowgwV5p+)y3jihV|C#+1A?9(JA-fnC00pDBx(7 zp?=60h|q*J3Zj)tPG!kl7lncCqwPk#y?HmvOj!?dpl=Jj|Ka=?=)@vg-K|IW_GO=~ z5KS@RfKdTC)>zfsoLnm{sh?AdycLzlVFu+My%u%&1tVHgn;g!H9^K^;^_OYZmd9CP zuyg<}UtEehKp$s-%Jfl$1znNRjj7di^Cyks904<>B(4~kz`8&rv3@t2^-kqS^~4n# zqljvS}=V|oLcmIqAn1WjJyYgsNv8%H&5Bq6S^TB5-~tAieqFpl7lsabVs1JRCD;}T z#K<;WCmq%|*ci-)-_Az2l<;y0Rk7il(nI_5iK&${sa)5v+t<}X+ncJ>8u2{srnp8%gAbP;tJHc)bwn=kfO0S{Wcwv)oj5i$2;3+3|Q zIB1022#~|vDA7-ip%iv?b?rWE7m7N;!Q8nYRH{|tb~Z4(QNGEKxb_a~m?@|E9`dne zj>r;Ihpqlpf+eHI=_+K|l0(AN#3+=~Q(vLiQt$lb?Ka-1zexPro73${O|yt_Pfkxq zeWnsiPPBVsA+Hr&AQ%+*lSHPdOu~=_N0(Gc4TiL&pn)Us^~=#QBbelRXmm%y9h z@ZGzN;&5sB)dlJ{m_c>~ZUa0W&!y7EdmV!)Kq$4I8VtAf z(vb$RKz8JQkgdGyk2vIjL%y{i$(kR!*@ZXUGASP96yAm45f2jShKGC^>l`C$gHF6; z5m1zo4&d8(0%c*qq6KUPa6zyCG#i=yXzZ;(*z8R8mg?!bijjJ@#$a%D?Jc7Hf7FRthx;KPIJCm!dF z`jD-J;sFM6hNX=c;LF=@HF3h&wzd{AnXzi^+AIEW6Fu>hE_#=KzbD^OVInWtivOlB zYUk942Z6k)pV@Kj1wa|EdV+PFwMIvP6RTN#w6(Uj9DCI8F{hv0y}cWhi|PCjMfb~# zuJ~Zy0-$Y;d^GKu*R&wJRKYue0~22(r|HN(Dy_{0BsBR>B#rKSi;97cH%x4tP&kRS zST(HnvaK~6G5ny@P98m=e?P=v52M`NKl#x+?tYM~K@>VRE)hp22Nn!Aaddg#NCW2D zu2`lDU@r0%+~*z|gLg7x(crGm&b4b+H#g)A(@jHP4qdnQw*DJ#xb4s(U)^QL!wx>M zcdzw`!VIvmmSf&W3op3zYBsq?;mfTnEiGAVYsO7f z9Gxm^8Bzd+ibS(&^;Mqv?9W7nr=NZCr{`Y0aN!a%Gl{I+m@|TkfHCL^01SEq`R1&_ z-}<2sh0q9X-ZiGSUKl~S_ArbK$D)=P3+2!uwS|cJ-GR%>XnScWeaYI}oBsHhORpSf zonWgNlETD1JWrSYXH51)z}L1VG*kv8a!}%4KnZSa`>*Xq+?Y@l6HmeO*0G_}={Xn< zl`qIG&v^A;8!5k+7%lLJA1%D_(yOOD_LPUrazqA(pqf=-`r3cdB<7C}i`DG9twE9~ zl!oz>DHPn8F&$Zz*O658{dc6p7l%oSnh{c3s2=l=;)DR%PX{Ykt-kq>lg5pov}*Ml z=9nldBcm`7&A~l^PBI`C_8E#Lg%S?f1n_N*UI!w&=(CE9wt6C(E9~D!N0kG08x7>% z;3sc$UhIb-&VOdwi&LL{;mN0-`+WII|G5Xd1gZIgGep8BR9mqV8ax{^7e`bm$5T}A zyIC%%HrjG9bVB2BdmukdO%&w4^zy5(y!vL;qMwe~~Lsu&ukffcipWFSH+bF+wXmVV@Y;ihqvG9ntqlUn<24WOHPKgN!95 z=$3;|w60VXk57Ge-1teMFr9}2i+CSYh8-5eVnq_^B4EA5bR$a?lytOZbmD^m>1a=c z>Hr`8l{QbTf75)##$%acQKph*PtYA@F@EXuc^w$@2VFo!8VPri-~c0Drn^^SFXfdW zT}c^c52ykOY7Xf10>&^Y0+}6x*jDq3>|(pisMPV)@h>E%U3~lLWEGibCgy_e1l6jE zn3()v*GQO5Ou8frEgdQrfyBxQU>3a)j0s9NU7SEe#t4!JTElwP1{BSdUCC5sf(4vk zL`|0-OR4|DNqm9~Ur^`+r;73@&QS;up*eLXIGrdT8=its64YEN4?g(Fyqu^y$dXpz z&9=E*Hm{?jgA!X@ZQWXF=>~N+)e)t56vp>!3w8vkT~8+jO;{L43=0H6Ce~ff6tje3 zTz3=BVF5{NBZ+a1 zit}fDm!2@4KDG#OQc<#M6xoPuXb?6l5%BJ=3dO}PqIlnL-z3nq7?Ba$hE+>h5I_{A zI4Lhg0o88j&6~eu>BoKY4;Th3x9v7tJ^$pri%l1ZVI9aA@uXGp$~v`l00eASCj=T0;2bw>|4>ct) zITrCt0HL_J2~^o7F}5jN15VayBAMt!ACQSXpz^C_UfDefOh`sXw_aH6N@G}eVIplI zv%+}}m?I@7ASZ;Nw|wALM-byWolD+Q z->K{l;4w2hU()17?l^kS#aZ-Sn3|7b;v!K|b?{GD1yND^42?TYYHS2R<)X{3S+jce ziKCCMR4P$bFe#+x%2=F<^+YLGY7E)01gUJ~#m?{u0A%t+ zl1Fwegqv)JDQJ8NRNaeZRtC7fAU8pzz?AeO7r=FNxD&_elF#f#@v;JMydOln!lYEL zw=4V{E)Jyyy@WLhb`m&muL4b8aP`~)f#PScQnJ25HGESm^Tx^_Rh2XE$!k}isEq18N z{*T#mfBGwLH|v z7#P4`%wUH0p^P*vThK(Ga8zX7{_eBkc_tJkO760pl!2DfHC8&0#5d_Pa~I2ikW`i| zK2P>$plq`!8idUSYNRtfJyZG#enZpTT=OFjkr_1!58tS#yVW_antC@}_Kv3X`44xV zhWQs)j3yh8Xm%v!3cRRstyQuyG1R3N4D zY>?%XTh&zXO;0Q1N;9|+tHAYu%-d+pOps$h-ab3mknreIKfvZp1UE7L$|q#Mk%@Y< zlrcymF8xsxFgDAG>y^tuqmRm@by9^rq$=l&9(9QrI<9a_AZt~ES%`De79(4g`Ng@( z!=k=@{cEv-x&0fC7ZYY{<#Wrh@4pQKT&&m}Nj!4p(sa4>3DZVx91R`k(5HX)LqDE< z^|j%=uc>K*s%-?mPskOM!pmdmC&=%bMTD5I+%W#)GxG<-j8yEjRc#N&8ZGNmi9;G z0U}bmBtW+HD zt>M=VZKcIb(>I154i~)dS$4397#sObLbhR_Q+a1Q!VtH%{@9lsn4Jp;w*QXh&#{1+ zWc=!l8KdP1_LS11JV)IFm-rCEPg?cWaQw3xZm)G!3h|3rRfD$~BZ1d7J(NDjGg1A)c_nVPN z7u!5CRzR2^r>R7?SKT)o7pQUFI4}Zy#IDj9&z~&&ZoX}f9ACME#-rH5?hA?6OUIG$ zfD)&C!eXf!156jt%2{*&Co3!V3UnZxHRf5rI}?1TsAr04=9`Q~ky7VlZ0uGBuM z{n@;D=#&^A#VUT_Vuhv#1U4S~7ewrzgGO*+KlJv*Do{!uD|U7NyzL|(p}camP&J?O zr|Z0wCTkzZ+8wtoqW*T^Y^1H(#cE}CE-A$!Pjg(Bn-KX3gA4;F%xP{PXQwmkNhf_q zoD%G;2Isxr<2}LSGAY>)Symb<(9NbBU`;j6APAoYBs^rfaqGe;1yUUTk@&opeA?#Z)&R9985N)7M(1NQxwFKq%l=W=AhPX6oxo$0TWTnmJtbVK-Gy#>hc4t2?{%{4pv3Kf_IvjG ztJalZdVN8i`gZtU^I=g0+-w>X&UKJKPeyovq^*$i{ z^^R=kQBGBc&#_NKVZ*~4$(?o9)hF+iavU&qZC@L7`Mb4x!9&YJ>R-tpI&;smJ#hAI z*%r0{KJpagcJWOJ@lZ$v@GR^kVmZtQ#VvI9#bZGVx@21BtY6f=uM5%t?IX$Chm(P5 z^Rx?>DtErM9)&pvgb(2wL-*BGZzcgcX4qKLinHmtj*4;ae{bV>qE<8s+x9WUEBrab zq5ALalcIt~5o7hwe|wv-adAKttD%Q8Q?$=;nYc)aC9n8IHU7M#gZ~O*xaN-jWOASils_BkYY|$KX<4l-{hB{vK{v5gW2L z@x7zy@hV0!?_yn(-Cb|i3tdJOOTz9(F7En_8~n++g;C)rAvVvx`d#Fr-^`jEsObN?L;4n4?1TJCyK&OmO|G?R|r6Vm;)^M6JUj|}_@j<>VS zEXw5OVT)GK>-$1uS=^GfGKU6jmj_PY+0c@VpE5vZEAdBCa@^ZJJ6{lp!Zbk|vq>Da z_|JpN{BNmur=!_(7QQv#!UDK3xEOUu4l__sLkZ|+RLObhY#Y6?<*;z=1;JY%Zw*I%V ziwGEVMPv<0kN@T(Fjub#FHkIzIgTZGa7kR}*2?WEPamuWd^2nH@Iyqmg$z o!~t}K{TvbTUsBuuBV*wy(<9E#Y?rQw|AH=q*>y`;y%8MqKX4^iDgXcg diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..faccfa86d2602d668a03985dfe869072ee9caee1 GIT binary patch literal 1750 zcmV;{1}XW8P)wxOZWu@1H$;&v(A_JKyVk-=Tsc z2E+eH2te2oIQ}34#h;WR^4ZD-J^lUoQnBvN-Oo2=GE!9&5g7p?G_1}s*=YD{uY`mI zx_rDj0qmkH3UgM?`QqntcRFkn4D=Q7V9i@P5MRB`I?N zz-sL{lz+kr1~9B&-z$YjcqU^2SS;;z^$pidg7osp<6%jS7*8z+y3Z8I9lW%!nBr z1%PHt`^GKVJN6uKVK$pBf8Q<>5kf$x^9T+KG#Wes;EmT`9r8l-tPhu8zE<2-BYv`C zfgKZ+mRHVBS$V6poPq6hl*;Pb(GzD%NziIFaj`>}FP=9rvcJE{XHRze$O$tls%kn# zCJ8GzuusCckpOW2!NVy@i)!odFf%-f#PuUD60KJ2&xIE*T)LLMbzNNSP;W2enq|pJ z$;;(2$-x>vELLMrR9|K7VK9mKtl-or{M`2B$-ITDPaNLeH#l(ku-Ndh(9*IBH(^B$ zjHCzo$4-l3K-paCN{?GxH)LdGrl%4@-X0addE3_xX%ZKVBrHFZuPs{=a;M?0=+#H; zUzOiK1*Z$mW{am@AM<>a^Mn%X9k7I;wOS1V63O!rIjLgQ{?uAkQy1Ak)MWDIO$at% zs#A%L)s<7o$>9>~JSYl)Sf4(1F5&M@UlBw$LD1eKhm7Z5L}VMT06*UzA;EzNSYBDp zE1cFj2b0MsdCs&>w?V+F>bj!^XT&85xCOA#HDV>~tJ<(3!2x;uv$J;XU%z=fT{ep0 zahO#AOX+qFxmDG5DN8?=Z!fRtr~wnkz8T&>6bQ_nG1=S8xGFVGR48EpxZS=w z>}WQduNIZa7b=CnUE02L-;_z?)+|fW={%-R8h8Ch$-%s1GE2JHRZAE{KplvC4;(J9 zsNS8GMp4>TOOj8V{^jAL$L_+Cv?+Z}sB2%(UAVkACwF>cg2}hX_%S2C$;ovWRyX&k zxbM3o(-RW_ATD-j7hp-=i*BO5{ZDyQbBn*9DI&a|OfTfN5#4T^Z3UdapRdWs2N4Ok z%w|c=RqaBmic{V~yu72D!qQT%98WMy6l~uK(Vvv1dYVNr4tv8S=z9|}al6QZOH zl-(KCn9`@mGg(`{hzRQo0J-@Ew@WKrRyzwE#Scm1QAdC6=&S^<;>YCIITiLg6BIYZdz(SW_{@D;PGQ3~e&2!QxvE2h&t%h#kY~@W&-ISz- zE%zTdn7GvnTh1d;=u#r`{a-FYFf5d07^E zys|DWbLqml9+cLdCu{|m0R8ad(k3E%`AAXruAD>p1i_@% literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e8a4b625d4be65f042e3003bdc485bbd4276d93b GIT binary patch literal 6143 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 R42%E(002ovPDHLkV1hoj>}UW0 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..f3aaf104834a114028c7022a463f405fd110d2af GIT binary patch literal 2153 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 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index 69f5fde3917b97004ae10614b8ce817a070d2723..c0cffe2b0f059571ba16ca23fc996723e1f20af2 100644 GIT binary patch literal 21953 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 Ye?_-L?8-8eIRF3v07*qoM6N<$g2MKcwg3PC literal 4178 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 X(10wfC2u;$00000NkvXXu0mjfG<_KC literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..586a567fdf0cb1e1c86330dcc7838baca08a2648 GIT binary patch literal 13517 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 Hu0mjf9;KZ) literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index a6c7c253b3007895dfe96fc9624316280b504bbc..eaefaf8c521785c0ad1e36d3a2fe275556ee89e0 100644 GIT binary patch literal 3507 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 literal 1814 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 TeEC1mKBuJyQ~mtnRm}eYnnKfW diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index bd4d3c1..777b9f4 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Bottlecrm CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -39,7 +41,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIViewControllerBasedStatusBarAppearance - + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/lib/app.dart b/lib/app.dart new file mode 100644 index 0000000..b635ecb --- /dev/null +++ b/lib/app.dart @@ -0,0 +1,158 @@ +import 'package:flutter/material.dart'; +import 'screens/login_screen.dart'; +import 'screens/dashboard_screen.dart'; +import 'screens/company_selection_screen.dart'; +import 'screens/company_create_screen.dart'; +import 'screens/lead_detail_screen.dart'; +import 'screens/lead_create_screen.dart'; +import 'screens/contacts_list_screen.dart'; +import 'screens/contact_create_screen.dart'; +import 'screens/contact_detail_screen.dart'; +import 'screens/tasks_list_screen.dart'; +import 'screens/task_create_screen.dart'; +import 'screens/task_detail_screen.dart'; +import 'screens/task_edit_screen.dart'; +import 'screens/about_screen.dart'; +import 'screens/help_support_screen.dart'; +import 'services/auth_service.dart'; +import 'services/leads_service.dart'; + +class BottleCrmApp extends StatelessWidget { + const BottleCrmApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'BottleCRM', + debugShowCheckedModeBanner: false, + theme: ThemeData( + colorScheme: ColorScheme.fromSeed( + seedColor: const Color(0xFF2563EB), // Blue color for CRM + brightness: Brightness.light, + ), + useMaterial3: true, + appBarTheme: const AppBarTheme(centerTitle: false, elevation: 0), + cardTheme: CardThemeData( + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), + ), + ), + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), + ), + ), + ), + home: const AuthWrapper(), + routes: { + '/login': (context) => const LoginScreen(), + '/company-selection': (context) => const CompanySelectionScreen(), + '/company-create': (context) => const CompanyCreateScreen(), + '/dashboard': (context) => const DashboardScreen(), + '/about': (context) => const AboutScreen(), + '/help-support': (context) => const HelpSupportScreen(), + '/contacts': (context) => const ContactsListScreen(), + '/contact-create': (context) => const ContactCreateScreen(), + '/contact-detail': (context) { + final contactId = + ModalRoute.of(context)!.settings.arguments as String; + return ContactDetailScreen(contactId: contactId); + }, + '/lead-detail': (context) { + final leadId = ModalRoute.of(context)!.settings.arguments as String; + return LeadDetailScreen(leadId: leadId); + }, + '/lead-create': (context) => const LeadCreateScreen(), + '/tasks': (context) => const TasksListScreen(), + '/task-create': (context) => const TaskCreateScreen(), + '/task-detail': (context) { + final taskId = ModalRoute.of(context)!.settings.arguments as String; + return TaskDetailScreen(taskId: taskId); + }, + '/task-edit': (context) { + final taskId = ModalRoute.of(context)!.settings.arguments as String; + return TaskEditScreen(taskId: taskId); + }, + }, + ); + } +} + +class AuthWrapper extends StatefulWidget { + const AuthWrapper({super.key}); + + @override + State createState() => _AuthWrapperState(); +} + +class _AuthWrapperState extends State { + final AuthService _authService = AuthService(); + final LeadsService _leadsService = LeadsService(); + bool _isInitializing = true; + + @override + void initState() { + super.initState(); + _initializeAuth(); + } + + Future _initializeAuth() async { + try { + await _authService.initialize(); + await _leadsService.initialize(); + } catch (e) { + debugPrint('Auth initialization error: $e'); + } finally { + if (mounted) { + setState(() { + _isInitializing = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + if (_isInitializing) { + return const MaterialApp( + home: Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularProgressIndicator(), + SizedBox(height: 16), + Text('Loading BottleCRM...'), + ], + ), + ), + ), + ); + } + + // Check authentication status and organization selection + if (!_authService.isLoggedIn) { + return const LoginScreen(); + } + + // If logged in but no organization selected, show company selection + if (!_authService.hasSelectedOrganization) { + return const CompanySelectionScreen(); + } + + // If logged in and organization selected, show dashboard + return const DashboardScreen(); + } +} diff --git a/lib/bloc/account_bloc.dart b/lib/bloc/account_bloc.dart deleted file mode 100644 index 96ec181..0000000 --- a/lib/bloc/account_bloc.dart +++ /dev/null @@ -1,331 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/services/crm_services.dart'; - -class AccountBloc { - List _openAccounts = []; - List _closedAccounts = []; - Account? _currentAccount; - String _currentAccountType = "Open"; - int? _currentAccountIndex; - String? _currentEditAccountId = ""; - Map _currentEditAccount = { - "name": "", - "website": "", - "phone": "", - "email": "", - "lead": null, - "billing_address_line": "", - "billing_street": "", - "billing_postcode": "", - "billing_city": "", - "billing_state": "", - "billing_country": null, - "contacts": [], - "teams": [], - "assigned_to": [], - "status": "open", - "tags": [], - "description":"", - }; - String _offset = ""; - - List _assignedToList = []; - List countriesList = []; - List? _tags = []; - List _filterTags = []; - - Future fetchAccounts({filtersData}) async { - try { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (filtersData != null) { - _copyFiltersData!['tags'] = _copyFiltersData['tags'].length > 0 - ? jsonEncode(_copyFiltersData['tags']) - : ""; - } - await CrmService() - .getAccounts(queryParams: _copyFiltersData, offset: _offset) - .then((response) { - var res = (json.decode(response.body)); - _assignedToList.clear(); - - res['active_accounts']['open_accounts'].forEach((_account) { - leadBloc.countriesList!.forEach((country) { - if (_account!["billing_country"] == country[0]) { - _account!["billing_country"] = country[1]; - } - }); - Account account = Account.fromJson(_account); - _openAccounts.add(account); - }); - res['closed_accounts']['close_accounts'].forEach((_account) { - leadBloc.countriesList!.forEach((country) { - if (_account!["billing_country"] == country[0]) { - _account!["billing_country"] = country[1]; - } - }); - Account account = Account.fromJson(_account); - _closedAccounts.add(account); - }); - if (res['users'] != null) - res['users'].forEach((_user) { - Profile user = Profile.fromJson(_user); - _assignedToList.add({"name": user.firstName, "id": user.id}); - }); - _filterTags = res['tags'] != null ? res['tags'] : []; - _offset = res['active_accounts']['offset'] != null && - res['active_accounts']['offset'].toString() != "0" - ? res['active_accounts']['offset'].toString() - : res['closed_accounts']['offset'] != null && - res['closed_accounts']['offset'].toString() != "0" - ? res['closed_accounts']['offset'].toString() - : ""; - }).catchError((onError) { - print("fetchAccounts Error>> $onError"); - }); - } catch (e) {} - } - - Future createAccount({File? file}) async { - print(_currentEditAccount); - try { - Map result = {}; - Map _copyCurrentEditAccount = new Map.from(_currentEditAccount); - _copyCurrentEditAccount['contacts'] = (_copyCurrentEditAccount['contacts'] - .map((contact) => contact.toString())).toList().toString(); - _copyCurrentEditAccount['teams'] = (_copyCurrentEditAccount['teams'] - .map((team) => team.toString())).toList().toString(); - _copyCurrentEditAccount['assigned_to'] = - (_copyCurrentEditAccount['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - _copyCurrentEditAccount['status'] = - _copyCurrentEditAccount['status'].toLowerCase(); - leadBloc.countriesList!.forEach((country) { - if (country![1] == _copyCurrentEditAccount['billing_country']) { - _copyCurrentEditAccount['billing_country'] = country[0]; - } - }); - leadBloc.openLeads.forEach((lead) { - if (lead.title == _copyCurrentEditAccount['lead']) { - _copyCurrentEditAccount['lead'] = lead.id.toString(); - } - }); - _copyCurrentEditAccount['tags'] = - jsonEncode(_copyCurrentEditAccount['tags']); - print(_copyCurrentEditAccount); - await CrmService() - .createAccount(_copyCurrentEditAccount, file!) - .then((response) async { - print(_copyCurrentEditAccount); - var res = json.decode(response.body); - if (res["error"] == false) { - offset = ""; - await fetchAccounts(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }) - .catchError((onError) { - print("createAccount Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } catch (e) {} - } - - Future editAccount() async { - Map? result; - Map _copyCurrentEditAccount = new Map.from(_currentEditAccount); - countriesList = leadBloc.countries; - _copyCurrentEditAccount['contacts'] = (_copyCurrentEditAccount['contacts'] - .map((contact) => contact.toString())).toList().toString(); - _copyCurrentEditAccount['teams'] = (_copyCurrentEditAccount['teams'] - .map((team) => team.toString())).toList().toString(); - _copyCurrentEditAccount['assigned_to'] = - (_copyCurrentEditAccount['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - _copyCurrentEditAccount['status'] = - _copyCurrentEditAccount['status'].toLowerCase(); - leadBloc.countriesList!.forEach((country) { - if (country![1] == _copyCurrentEditAccount['billing_country']) { - _copyCurrentEditAccount['billing_country'] = country[0]; - } - }); - leadBloc.openLeads.forEach((lead) { - if (lead.title == _copyCurrentEditAccount['lead']) { - _copyCurrentEditAccount['lead'] = lead.id.toString(); - } - }); - _copyCurrentEditAccount['tags'] = - jsonEncode(_copyCurrentEditAccount['tags']); - await CrmService() - .editAccount(_copyCurrentEditAccount, _currentEditAccountId) - .then((response) async { - var res = json.decode(response.body); - if (res["error"] == false) { - offset = ""; - await fetchAccounts(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }).catchError((onError) { - print("editAccount Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - Future deleteAccount(Account account) async { - Map? result = {}; - await CrmService().deleteAccount(account.id).then((response) async { - var res = (json.decode(response.body)); - await fetchAccounts(); - await dashboardBloc.fetchDashboardDetails(); - result = res; - }).catchError((onError) { - print("deleteAccount Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - resetAccountFields() { - _currentEditAccountId = null; - _currentEditAccount = { - "name": "", - "website": "", - "phone": "", - "email": "", - "lead": null, - "billing_address_line": "", - "billing_street": "", - "billing_postcode": "", - "billing_city": "", - "billing_state": "", - "billing_country": null, - "contacts": [], - "teams": [], - "assigned_to": [], - "status": "open", - "tags": [], - }; - _tags = []; - } - - updateCurrentEditAccount(Account editAccount) { - List contacts = []; - List teams = []; - List assignedUsers = []; - List? tags = []; - _currentEditAccountId = editAccount.id.toString(); - editAccount.contacts!.forEach((contact) { - contacts.add(contact.id); - }); - - editAccount.assignedTo!.forEach((assignedAccount) { - assignedUsers.add(assignedAccount.id); - }); - - editAccount.teams!.forEach((team) { - teams.add(team.id); - }); - - editAccount.tags!.forEach((tag) { - tags.add(tag['name']!); - }); - - _currentEditAccount['name'] = editAccount.name; - _currentEditAccount['website'] = editAccount.website; - _currentEditAccount['phone'] = editAccount.phone; - _currentEditAccount['email'] = editAccount.email; - _currentEditAccount['lead'] = editAccount.lead!.title; - _currentEditAccount['billing_address_line'] = - editAccount.billingAddressLine; - _currentEditAccount['billing_street'] = editAccount.billingStreet; - _currentEditAccount['billing_postcode'] = editAccount.billingPostcode; - _currentEditAccount['billing_city'] = editAccount.billingCity; - _currentEditAccount['billing_state'] = editAccount.billingState; - _currentEditAccount['billing_country'] = editAccount.billingCountry; - _currentEditAccount['contacts'] = contacts; - _currentEditAccount['teams'] = teams; - _currentEditAccount['assigned_to'] = assignedUsers; - _currentEditAccount['status'] = editAccount.status; - _currentEditAccount['tags'] = tags; - _tags = tags; - } - - List get openAccounts { - return _openAccounts; - } - - List get closedAccounts { - return _closedAccounts; - } - - List get assignedToList { - return _assignedToList; - } - - Map get currentEditAccount { - return _currentEditAccount; - } - - set currentEditAccount(currentEditAccount) { - _currentEditAccount = currentEditAccount; - } - - List? get tags { - return _tags; - } - - List get filterTags { - return _filterTags; - } - - String? get currentEditAccountId { - return _currentEditAccountId; - } - - set currentEditAccountId(id) { - _currentEditAccountId = id; - } - - Account? get currentAccount { - return _currentAccount; - } - - set currentAccount(account) { - _currentAccount = account; - } - - int? get currentAccountIndex { - return _currentAccountIndex; - } - - set currentAccountIndex(index) { - _currentAccountIndex = index; - } - - String get currentAccountType { - return _currentAccountType; - } - - set currentAccountType(type) { - _currentAccountType = type; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final accountBloc = AccountBloc(); diff --git a/lib/bloc/auth_bloc.dart b/lib/bloc/auth_bloc.dart deleted file mode 100644 index fa3c206..0000000 --- a/lib/bloc/auth_bloc.dart +++ /dev/null @@ -1,215 +0,0 @@ -import 'dart:convert'; - -import 'package:bottle_crm/model/organization.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:google_sign_in/google_sign_in.dart'; - -class AuthBloc { - String? _subDomainName; - String? _authToken; - Profile? _userProfile; - List _companies = []; - Organization? _selectedOrganization; - - String? get subDomainName { - return _subDomainName; - } - - String? get authToken { - return _authToken; - } - - Profile? get userProfile { - return _userProfile; - } - - List get companies { - return _companies; - } - - Organization? get selectedOrganization { - return _selectedOrganization; - } - - set selectedOrganization(selectedOrganization) { - _selectedOrganization = selectedOrganization; - } - - Future validateDomain(data) async { - Map? result; - await CrmService().validateSubdomain(data).then((response) { - var res = (json.decode(response.body)); - if (res['error'] == false) { - _subDomainName = data['sub_domain']; - result = res; - } else { - result = res; - } - }).catchError((onError) { - print("validate domain error>> $onError"); - result = {"status": "error", "message": "Something went wrong"}; - }); - return result; - } - - Future googleLogin() async { - try { - Map result = {}; - final SharedPreferences preferences = - await SharedPreferences.getInstance(); - - // Initialize Google Sign-In - final GoogleSignIn googleSignIn = GoogleSignIn( - scopes: ['email', 'profile'], - ); - - // Sign in with Google - final GoogleSignInAccount? googleUser = await googleSignIn.signIn(); - if (googleUser == null) { - return {"error": true, "message": "Google sign-in was cancelled"}; - } - - // Get authentication details - final GoogleSignInAuthentication googleAuth = await googleUser.authentication; - final String? idToken = googleAuth.idToken; - - if (idToken == null) { - return {"error": true, "message": "Failed to get Google ID token"}; - } - - // Send token to backend - await CrmService().googleLogin(idToken).then((response) async { - var res = (json.decode(response.body)); - print("=== LOGIN RESPONSE DEBUG ==="); - print("Status Code: ${response.statusCode}"); - print("Response Body: ${response.body}"); - print("============================"); - - if (response.statusCode == 200 && res['success'] == true && res['JWTtoken'] != null) { - _authToken = "Bearer " + res['JWTtoken']; - preferences.setString("authToken", _authToken!); - - // Store user profile data if available - if (res['user'] != null) { - _userProfile = Profile.fromJson(res['user']); - } - - // Store organizations list - if (res['organizations'] != null) { - _companies.clear(); - for (var org in res['organizations']) { - Organization organization = Organization.fromJson(org); - _companies.add(organization); - } - } - - result = {"error": false, "token": res['JWTtoken'], "user": res['user'], "organizations": res['organizations']}; - } else { - result = {"error": true, "message": res['message'] ?? "Login failed"}; - } - }).catchError((onError) { - print("google login error>> $onError"); - result = {"error": true, "message": "Network Error, check your internet"}; - }); - return result; - } catch (e) { - print("google login error>> $e"); - return {"error": true, "message": "Google login failed. Please try again."}; - } - } - - Future forgotPassword(data) async { - Map? result; - await CrmService().forgotPassword(data).then((response) { - var res = (json.decode(response.body)); - result = res; - }).catchError((onError) { - print("forgot password Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - Future register(data) async { - Map? result = {}; - await CrmService().userRegister(data).then((response) async { - var res = (json.decode(response.body)); - if (res['error'] == false) { - result = res; - } else { - result = res; - } - }).catchError((onError) { - print("register user error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - Future getProfileDetails() async { - await CrmService().getUserProfile().then((response) { - var res = (json.decode(response.body)); - if (res['user_obj'] != null) { - _userProfile = Profile.fromJson(res['user_obj']); - } else { - _userProfile = null; - } - }).catchError((onError) { - print("get profile Error >> $onError"); - }); - } - - Future changePassword(data) async { - Map result = {}; - await CrmService().changePassword(data).then((response) { - var res = (json.decode(response.body)); - result = res; - }).catchError((onError) { - print("change password Error >> $onError"); - result = {"status": "error", "message": "Something went wrong"}; - }); - return result; - } - - Future fetchCompanies() async { - try { - await CrmService().getCompanies().then((response) { - var res = (json.decode(response.body)); - if (res['error'] == false) { - _companies.clear(); - res['companies'].forEach((_company) { - Organization company = Organization.fromJson(_company); - _companies.add(company); - }); - } - }).catchError((onError) { - print("companies list error>> $onError"); - }); - } catch (e) { - } - - } - - Future clearAllStoredData() async { - final SharedPreferences preferences = await SharedPreferences.getInstance(); - - // Clear all stored preferences - await preferences.remove('authToken'); - await preferences.remove('org'); - await preferences.remove('userProfile'); - await preferences.remove('selectedOrganization'); - - // Clear bloc state variables - _authToken = null; - _userProfile = null; - _companies.clear(); - _selectedOrganization = null; - _subDomainName = null; - - print("All stored data cleared successfully"); - } -} - -final authBloc = AuthBloc(); diff --git a/lib/bloc/case_bloc.dart b/lib/bloc/case_bloc.dart deleted file mode 100644 index e80956c..0000000 --- a/lib/bloc/case_bloc.dart +++ /dev/null @@ -1,318 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/model/case.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:bottle_crm/model/team.dart'; - -class CaseBloc { - int? _casesCount; - List _cases = []; - List _assignedUsers = []; - List _teams = []; - List _statusObjForDropDown = []; - List _priorityObjForDropDown = []; - List _typeOfCaseObjForDropDown = []; - List _accountsObjForDropDown = []; - Case? _currentCase; - String _offset = ""; - List _teamsObjForDropdown = []; - List _assignedUsersDropdown = []; - Map _currentEditCase = { - 'name': "", - 'status': "", - 'priority': "", - 'type_of_case': "", - 'account': "", - 'contacts': [], - 'closed_on': DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())), - 'description': "", - 'assigned_to': [], - 'teams': [], - }; - String? _currentEditCaseId; - - Future fetchCases({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (filtersData != null) { - if (_copyFiltersData!['account'] != null) { - opportunityBloc.accountsList.forEach((element) { - if (element[1] == _copyFiltersData['account']) { - _copyFiltersData['account'] = element[0].toString(); - } - }); - } - } - - await CrmService() - .getCases(queryParams: _copyFiltersData, offset: _offset) - .then((response) { - var res = json.decode(response.body); - // _cases.clear(); - _casesCount = res['cases_count']; - - res['cases'].forEach((_case) { - Case data = Case.fromJson(_case); - _cases.add(data); - }); - - if (_copyFiltersData == null) { - if (res['status'] != null) { - _statusObjForDropDown.clear(); - res['status'].forEach((_status) { - _statusObjForDropDown.add(_status[1]); - }); - } - if (res['priority'] != null) { - _priorityObjForDropDown.clear(); - res['priority'].forEach((_priority) { - _priorityObjForDropDown.add(_priority[1]); - }); - } - - if (res['type_of_case'] != null) { - _typeOfCaseObjForDropDown.clear(); - res['type_of_case'].forEach((_typeOfCase) { - _typeOfCaseObjForDropDown.add(_typeOfCase[1]); - }); - } - - _teams.forEach((_team) { - Map team = {}; - team['id'] = _team.id; - team['name'] = _team.name; - _teamsObjForDropdown.add(team); - }); - - _assignedUsers.forEach((_user) { - Map user = {}; - user['id'] = _user.id; - user['name'] = _user.firstName; - _assignedUsersDropdown.add(user); - }); - - - - // _priorityObjForDropDown = res['priority']; - // _typeOfCaseObjForDropDown = res['type_of_case']; - } - }).catchError((onError) { - print("fetchCases Error >> $onError"); - }); - } - - Future deleteCase(Case data) async { - Map? result; - await CrmService() - .deletefromModule('cases', data.id) - .then((response) async { - var res = (json.decode(response.body)); - await fetchCases(); - // await dashboardBloc.fetchDashboardDetails(); - result = res; - }).catchError((onError) { - print("deleteCase Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - cancelCurrentEditCase() { - _currentEditCaseId = null; - _currentEditCase = { - 'name': "", - 'status': "", - 'priority': "", - 'type_of_case': "", - 'account': "", - 'contacts': [], - 'closed_on': "", - 'description': "", - 'assigned_to': [], - 'teams': [], - }; - } - - Future createCase({File? file}) async { - Map? result; - Map _copyOfCurrentEditCase = Map.from(_currentEditCase); - - opportunityBloc.accountsList.forEach((element) { - if (element[1] == _copyOfCurrentEditCase['account']) { - _copyOfCurrentEditCase['account'] = element[0].toString(); - } - }); - _copyOfCurrentEditCase['teams'] = (_copyOfCurrentEditCase['teams'] - .map((e) => e.toString())).toList().toString(); - _copyOfCurrentEditCase['assigned_to'] = - (_copyOfCurrentEditCase['assigned_to'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditCase['contacts'] = (_copyOfCurrentEditCase['contacts'] - .map((e) => e.toString())).toList().toString(); - - // if (_copyOfCurrentEditCase['closed_on'] != "") { - // _copyOfCurrentEditCase['closed_on'] = DateFormat("yyyy-MM-dd").format( - // DateFormat("dd-MM-yyyy").parse(_copyOfCurrentEditCase['closed_on'])); - // } - await CrmService() - .createCase(_copyOfCurrentEditCase, file!) - .then((response) async { - // var res = json.decode(response); # for multipartrequest - var res = json.decode(response.body); - if (res["error"] == false) { - //await fetchCases(); - await fetchRequiredData(); - } - result = res; - }).catchError((onError) { - print("createCases Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - updateCurrentEditCase(Case editCase) { - List _contacts = []; - List _teams = []; - List _assignedUsers = []; - - _currentEditCaseId = editCase.id.toString(); - editCase.contacts!.forEach((contact) { - _contacts.add(contact.id); - }); - editCase.assignedTo!.forEach((assignedAccount) { - _assignedUsers.add(assignedAccount.id); - }); - editCase.teams!.forEach((team) { - _teams.add(team.id); - }); - - _currentEditCase = { - 'name': editCase.name, - 'status': editCase.status, - 'priority': editCase.priority, - 'type_of_case': editCase.caseType, - 'account': editCase.account!.name, - 'contacts': _contacts, - 'closed_on': DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(editCase.closedOn!)), - 'description': editCase.description, - 'assigned_to': _assignedUsers, - 'teams': _teams, - }; - } - - Future editCase([file]) async { - Map? result; - Map _copyOfCurrentEditCase = Map.from(_currentEditCase); - - opportunityBloc.accountsList.forEach((element) { - if (element[1] == _copyOfCurrentEditCase['account']) { - _copyOfCurrentEditCase['account'] = element[0].toString(); - } - }); - _copyOfCurrentEditCase['teams'] = (_copyOfCurrentEditCase['teams'] - .map((e) => e.toString())).toList().toString(); - _copyOfCurrentEditCase['assigned_to'] = - (_copyOfCurrentEditCase['assigned_to'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditCase['contacts'] = (_copyOfCurrentEditCase['contacts'] - .map((e) => e.toString())).toList().toString(); - - if (_copyOfCurrentEditCase['closed_on'] != "") { - _copyOfCurrentEditCase['closed_on'] = DateFormat("yyyy-MM-dd").format( - DateFormat("dd-MM-yyyy").parse(_copyOfCurrentEditCase['closed_on'])); - } - - _copyOfCurrentEditCase - .removeWhere((key, value) => value.runtimeType != String); - - await CrmService() - .editCase(_copyOfCurrentEditCase, _currentEditCaseId, file) - .then((response) async { - var res = json.decode(response.body); - if (res["error"] == false) { - await fetchCases(); - } - result = res; - }).catchError((onError) { - print("editCase Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - List get cases { - return _cases; - } - - List get statusObjForDropDown { - return _statusObjForDropDown; - } - - List get priorityObjForDropDown { - return _priorityObjForDropDown; - } - - List get typeOfCaseObjForDropDown { - return _typeOfCaseObjForDropDown; - } - - List get accountCaseObjForDropDown { - return _accountsObjForDropDown; - } - - int? get casesCount { - return _casesCount; - } - - Map get currentEditCase { - return _currentEditCase; - } - - String? get currentEditCaseId { - return _currentEditCaseId; - } - - set currentEditCaseId(id) { - _currentEditCaseId = id; - } - - Case? get currentCase { - return _currentCase; - } - - set currentCase(data) { - _currentCase = data; - } - - List get teamsObjForDropdown { - return _teamsObjForDropdown; - } - - List get assignedUsersDropdown { - return _assignedUsersDropdown; - } - - List get teams { - return _teams; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final caseBloc = CaseBloc(); diff --git a/lib/bloc/contact_bloc.dart b/lib/bloc/contact_bloc.dart deleted file mode 100644 index 9a4458b..0000000 --- a/lib/bloc/contact_bloc.dart +++ /dev/null @@ -1,366 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:intl/intl.dart'; - -import 'dashboard_bloc.dart'; - -class ContactBloc { - List _contacts = []; - List _contactsObjForDropdown = []; - List _teams = []; - List _teamsObjForDropdown = []; - String? _currentEditContactId; - Contact? _currentContact; - int? _currentContactIndex; - List countriesList = accountBloc.countriesList; - List _assignedToList = []; - - Map _currentEditContact = { - 'salutation': "", - 'first_name': "", - 'last_name': "", - 'primary_email': "", - 'mobile_number': "", - 'date_of_birth': DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())), - 'organization': "", - 'department': "", - 'do_not_call': false, - 'title': "", - 'address': { - "address_line": "", - "street": "", - "city": "", - "state": "", - "pincode": "", - "country": "" - }, - 'linked_in_url': "", - 'facebook_url': "", - 'twitter_username': "", - 'description': "", - 'assigned_to': [], - 'teams': [], - }; - String _offset = ""; - - Future fetchContacts({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (filtersData != null) { - _copyFiltersData!['assigned_to'] = - _copyFiltersData['assigned_to'].length > 0 - ? jsonEncode(_copyFiltersData['assigned_to']) - : ""; - } - await CrmService() - .getContacts(queryParams: _copyFiltersData, offset: _offset) - .then((response) { - var res = json.decode(response.body); - // _contacts.clear(); - _contactsObjForDropdown.clear(); - _teams.clear(); - _assignedToList.clear(); - res['contact_obj_list'].forEach((_contact) { - leadBloc.countriesList!.forEach((country) { - if (_contact!['address'] != null && - _contact['address']['country'] != null && - _contact['address']['country'] == country[0]) { - _contact!['address']['country'] = country[1]; - } - }); - Contact contact = Contact.fromJson(_contact); - _contacts.add(contact); - }); - - _offset = res['offset'] != null && res['offset'].toString() != "0" - ? res['offset'].toString() - : ""; - - _contacts.forEach((_contact) { - Map contact = {}; - contact['id'] = _contact.id; - contact['name'] = _contact.firstName! + ' ' + _contact.lastName!; - _contactsObjForDropdown.add(contact); - }); - if (res['teams'] != null) - res['teams'].forEach((_team) { - Team team = Team.fromJson(_team); - _teams.add(team); - }); - - _teams.forEach((_team) { - Map team = {}; - team['id'] = _team.id; - team['name'] = _team.name; - _teamsObjForDropdown.add(team); - }); - // if (res['users'] != null) - // res['users'].forEach((_user) { - // Profile user = Profile.fromJson(_user); - // _assignedToList.add({"name": user.firstName, "id": user.id}); - // }); - }).catchError((onError) { - print("fetchContacts Error>> $onError"); - }); - } - - createContact({File? file}) async { - Map result = {}; - leadBloc.countriesList!.forEach((country) { - if (country[1] == _currentEditContact['address']['country']) { - _currentEditContact['address']['country'] = country[0]; - } - }); - // Map _copyOfCurrentEditContact= new Map.from(_currentEditContact); - Map _contact = { - 'salutation': _currentEditContact['salutation'], - 'first_name': _currentEditContact['first_name'], - 'last_name': _currentEditContact['last_name'], - 'mobile_number': _currentEditContact['mobile_number'], - 'primary_email': _currentEditContact['primary_email'], - 'title': _currentEditContact['title'], - 'linked_in_url': _currentEditContact['linked_in_url'], - 'facebook_url': _currentEditContact['facebook_url'], - 'twitter_username': _currentEditContact['twitter_username'], - 'organization': _currentEditContact['organization'], - 'department': _currentEditContact['department'], - 'date_of_birth': _currentEditContact['date_of_birth'], - 'do_not_call': _currentEditContact['do_not_call'], - 'teams': _currentEditContact['teams'], - 'assigned_to': _currentEditContact['assigned_to'], - 'address_line': (_currentEditContact['address'])['address_line'], - 'street': _currentEditContact['address']['street'], - 'city': _currentEditContact['address']['city'], - 'state': _currentEditContact['address']['state'], - 'pincode': _currentEditContact['address']['pincode'], - 'country': _currentEditContact['address']['country'], - 'description': _currentEditContact['description'], - // 'contact_attachment' : '', - }; - - _contact['teams'] = - (_contact['teams'].map((team) => team.toString())).toList().toString(); - _contact['assigned_to'] = (_contact['assigned_to'] - .map((team) => team.toString())).toList().toString(); - _contact['do_not_call'] = _contact['do_not_call'].toString(); - await CrmService().createContact(_contact, file!).then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - //await fetchContacts(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }).catchError((onError) { - print('createContact Error >> $onError'); - result = {"status": "error", "message": onError}; - }); - return result; - } - - editContact() async { - Map? _result; - Map copyOfCurrentEditContact = { - 'salutation': _currentEditContact['salutation'], - 'first_name': _currentEditContact['first_name'], - 'last_name': _currentEditContact['last_name'], - 'mobile_number': _currentEditContact['mobile_number'], - 'primary_email': _currentEditContact['primary_email'], - 'title': _currentEditContact['title'], - 'linked_in_url': _currentEditContact['linked_in_url'], - 'facebook_url': _currentEditContact['facebook_url'], - 'twitter_username': _currentEditContact['twitter_username'], - 'organization': _currentEditContact['organization'], - 'department': _currentEditContact['department'], - 'date_of_birth': _currentEditContact['date_of_birth'], - 'do_not_call': _currentEditContact['do_not_call'], - 'teams': _currentEditContact['teams'], - 'assigned_to': _currentEditContact['assigned_to'], - 'address_line': (_currentEditContact['address'])['address_line'], - 'street': _currentEditContact['address']['street'], - 'city': _currentEditContact['address']['city'], - 'state': _currentEditContact['address']['state'], - 'pincode': _currentEditContact['address']['pincode'], - 'country': _currentEditContact['address']['country'], - 'description': _currentEditContact['description'], - // 'contact_attachment' : '', - }; - countriesList.forEach((country) { - if (country![1] == copyOfCurrentEditContact['country']) { - copyOfCurrentEditContact['country'] = country[0]; - } - }); - - copyOfCurrentEditContact['teams'] = - jsonEncode(copyOfCurrentEditContact['teams']); - copyOfCurrentEditContact['assigned_to'] = - jsonEncode(copyOfCurrentEditContact['assigned_to']); - await CrmService() - .editContact(copyOfCurrentEditContact, currentEditContactId) - .then((response) async { - var res = json.decode(response.body); - - if (res['error'] == false) { - await fetchContacts(); - await dashboardBloc.fetchDashboardDetails(); - } - _result = res; - }).catchError((onError) { - print('editContact Error >> $onError'); - _result = {"status": "error", "message": onError}; - }); - return _result; - } - - Future deleteContact(Contact contact) async { - Map? result; - await CrmService().deleteContact(contact.id).then((response) async { - var res = (json.decode(response.body)); - await fetchContacts(); - await dashboardBloc.fetchDashboardDetails(); - result = res; - }).catchError((onError) { - print("deleteContact Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - cancelCurrentEditContact() { - _currentEditContactId = null; - _currentEditContact = { - 'salutation': "", - 'first_name': "", - 'last_name': "", - 'primary_email': "", - 'mobile_number': "", - 'title': "", - 'linked_in_url': '', - 'facebook_url': '', - 'twitter_username': '', - 'organization': '', - 'department': '', - 'date_of_birth': DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())), - 'do_not_call': false, - 'address': { - "address_line": "", - "street": "", - "city": "", - "state": "", - "pincode": "", - "country": "" - }, - 'description': "", - 'assigned_to': [], - 'teams': [], - }; - } - - updateCurrentEditContact(Contact editContact) { - _currentEditContactId = editContact.id.toString(); - List teams = []; - List assignedUsers = []; - - editContact.teams!.forEach((team) { - teams.add(team.id); - }); - - editContact.assignedTo!.forEach((user) { - assignedUsers.add(user.id); - }); - _currentEditContact['salutation'] = editContact.salutation; - _currentEditContact['id'] = editContact.id; - _currentEditContact['first_name'] = editContact.firstName; - _currentEditContact['last_name'] = editContact.lastName; - _currentEditContact['primary_email'] = editContact.primaryEmail; - _currentEditContact['mobile_number'] = editContact.primaryMobile; - _currentEditContact['title'] = editContact.title; - _currentEditContact['linked_in_url'] = editContact.linkedInUrl; - _currentEditContact['facebook_url'] = editContact.facebookUrl; - _currentEditContact['twitter_username'] = editContact.twitterUserName; - _currentEditContact['organization'] = editContact.organization; - _currentEditContact['department'] = editContact.department; - _currentEditContact['date_of_birth'] = editContact.dateOfBirth; - _currentEditContact['do_not_call'] = editContact.doNotCall; - _currentEditContact['description'] = editContact.description; - _currentEditContact['created_by'] = editContact.createdBy; - _currentEditContact['created_on'] = editContact.createdOn; - _currentEditContact['is_active'] = editContact.isActive; - _currentEditContact['address'] = editContact.address; - countriesList.forEach((country) { - if (country![0] == editContact.address!['country']) { - _currentEditContact['address']['country'] = country[1]; - } - }); - _currentEditContact['teams'] = teams; - _currentEditContact['assigned_to'] = assignedUsers; - } - - Map get currentEditContact { - return _currentEditContact; - } - - set currentEditContact(currentEditContact) { - _currentEditContact = currentEditContact; - } - - List get contacts { - return _contacts; - } - - Contact? get currentContact { - return _currentContact; - } - - set currentContact(contact) { - _currentContact = contact; - } - - int? get currentContactIndex { - return _currentContactIndex; - } - - set currentContactIndex(currentContactIndex) { - _currentContactIndex = currentContactIndex; - } - - List get teams { - return _teams; - } - - List get contactsObjForDropdown { - return _contactsObjForDropdown; - } - - String? get currentEditContactId { - return _currentEditContactId; - } - - set currentEditContactId(id) { - _currentEditContactId = id; - } - - List get teamsObjForDropdown { - return _teamsObjForDropdown; - } - - List get assignedToList { - return _assignedToList; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final contactBloc = ContactBloc(); diff --git a/lib/bloc/dashboard_bloc.dart b/lib/bloc/dashboard_bloc.dart deleted file mode 100644 index 264a626..0000000 --- a/lib/bloc/dashboard_bloc.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'dart:convert'; -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/opportunities.dart'; -import 'package:bottle_crm/services/crm_services.dart'; - -class DashboardBloc { - Map _dashboardData = {}; - - Future fetchDashboardDetails() async { - await CrmService().getDashboardDetails().then((response) { - var res = (json.decode(response.body)); - - List _accounts = []; - List _opportunities = []; - List _contacts = []; - - res['accounts'].forEach((_account) { - Account account = Account.fromJson(_account); - _accounts.add(account); - }); - - res['contacts'].forEach((_contact) { - Contact contact = Contact.fromJson(_contact); - _contacts.add(contact); - }); - - res['opportunities'].forEach((_opportunity) { - Opportunity opportunity = Opportunity.fromJson(_opportunity); - _opportunities.add(opportunity); - }); - - _dashboardData['accounts'] = _accounts; - _dashboardData['opportunities'] = _opportunities; - _dashboardData['contacts'] = _contacts; - _dashboardData['accountsCount'] = res['accounts_count']; - _dashboardData['contactsCount'] = res['contacts_count']; - _dashboardData['leadsCount'] = res['leads_count']; - _dashboardData['opportunitiesCount'] = res['opportunities_count']; - }); - // .catchError((onError) { - // print("fetchDashboardDetails Error >> $onError"); - // }); - } - - Map get dashboardData { - return _dashboardData; - } -} - -final dashboardBloc = DashboardBloc(); diff --git a/lib/bloc/document_bloc.dart b/lib/bloc/document_bloc.dart deleted file mode 100644 index db5b99f..0000000 --- a/lib/bloc/document_bloc.dart +++ /dev/null @@ -1,212 +0,0 @@ -import 'dart:convert'; - -import 'package:bottle_crm/model/document.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/services/crm_services.dart'; - -class DocumentBloc { - List _activeDocuments = []; - List _inActiveDocuments = []; - List _documents = []; - List _fileSizes = []; - - List _statusObjforDropdown = []; - List _usersObjforMultiselect = []; - - Document? _currentDocument; - int? _currentDocumentIndex; - Map _currentEditDocument = { - 'title': "", - 'teams': [], - 'shared_to': [], - 'document_file': '' - }; - String? _currentEditDocumentId; - - fetchDocuments({searchData}) async { - Map? _copySearchData = searchData != null ? new Map.from(searchData) : null; - - await CrmService() - .getDocuments(queryParams: _copySearchData) - .then((response) async { - _activeDocuments.clear(); - _inActiveDocuments.clear(); - _documents.clear(); - _fileSizes.clear(); - _usersObjforMultiselect.clear(); - - var res = jsonDecode(response.body); - - res['documents_active'].forEach((_document) { - Document document = Document.fromJson(_document); - _activeDocuments.add(document); - _documents.add(document); - }); - res['documents_inactive'].forEach((_document) { - Document document = Document.fromJson(_document); - _inActiveDocuments.add(document); - _documents.add(document); - }); - - res['status_choices'].map((status) { - _statusObjforDropdown.add(status); - }); - - res['users'].forEach((_user) { - Profile user = Profile.fromJson(_user); - _usersObjforMultiselect.add({ - "name": "${user.firstName} ${user.lastName}", - "id": user.id.toString() - }); - }); - }).catchError((onError) { - print('fetchDocuments Error >> $onError'); - }); - - // _fileSizes = await CrmService().getFileSizes(_documents); - // print(fileSizes); - } - - createDocument(file) async { - Map? result; - Map _copyOfCurrentEditDocument = new Map.from(_currentEditDocument); - _copyOfCurrentEditDocument['teams'] = (_copyOfCurrentEditDocument['teams'] - .map((team) => team.toString())).toList().toString(); - _copyOfCurrentEditDocument['shared_to'] = - (_copyOfCurrentEditDocument['shared_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - await CrmService() - .createDocument(_copyOfCurrentEditDocument, file) - .then((response) async { - var res = json.decode(response); - if (res["error"] == false) { - await fetchDocuments(); - } - result = res; - }).catchError((onError) { - print("editDocument Error >> $onError"); - result = {"status": "error", "message": "Something went wrong"}; - }); - return result; - } - - Future editDocument(file) async { - Map? result; - Map _copyOfCurrentEditDocument = Map.from(_currentEditDocument); - _copyOfCurrentEditDocument['teams'] = (_copyOfCurrentEditDocument['teams'] - .map((team) => team.toString())).toList().toString(); - _copyOfCurrentEditDocument['shared_to'] = - (_copyOfCurrentEditDocument['shared_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - await CrmService() - .editDocument(_copyOfCurrentEditDocument, file, _currentEditDocumentId) - .then((response) async { - var res = json.decode(response); - if (res["error"] == false) { - await fetchDocuments(); - } - result = res; - }).catchError((onError) { - print("editDocument Error >> $onError"); - result = {"status": "error", "message": "Something went wrong"}; - }); - return result; - } - - deleteDocument(Document file) async { - Map? result; - await CrmService().deleteDocument(file.id).then((response) async { - var res = (json.decode(response.body)); - await fetchDocuments(); - result = res; - }).catchError((onError) { - print("deleteDocument Error >> $onError"); - result = { - "status": "error", - "message": "deleteDocument : Something went wrong." - }; - }); - return result; - } - - cancelCurrentEditDocument() { - _currentEditDocumentId = null; - _currentEditDocument = {'title': "", 'teams': [], 'shared_to': []}; - } - - updateCurrentEditDocument(Document editFile) { - _currentEditDocumentId = editFile.id.toString(); - List sharedToList = []; - List teams = []; - - editFile.sharedTo!.forEach((sharee) { - sharedToList.add(sharee.id.toString()); - }); - - editFile.teams!.forEach((team) { - teams.add(team.id); - }); - - _currentEditDocument['title'] = editFile.title; - _currentEditDocument['document_file'] = editFile.documentFile; - _currentEditDocument['teams'] = teams; - _currentEditDocument['shared_to'] = sharedToList; - _currentEditDocument['status'] = editFile.status; - } - - List get documents { - return _documents; - } - - List get activeDocuments { - return _activeDocuments; - } - - List get inActiveDocuments { - return _inActiveDocuments; - } - - List get fileSizes { - return _fileSizes; - } - - List get statusObjforDropdown { - return _statusObjforDropdown; - } - - List get usersObjforMultiselect { - return _usersObjforMultiselect; - } - - Document? get currentDocument { - return _currentDocument; - } - - set currentDocument(document) { - _currentDocument = document; - } - - int? get currentDocumentIndex { - return _currentDocumentIndex; - } - - set currentDocumentIndex(index) { - _currentDocumentIndex = index; - } - - String? get currentEditDocumentId { - return _currentEditDocumentId; - } - - Map get currentEditDocument { - return _currentEditDocument; - } - - set currentEditDocumentId(id) { - _currentEditDocumentId = id; - } - // --------------------------DOCUMENT DOWNLOAD METHODS---------------- - -} - -final documentBLoc = DocumentBloc(); diff --git a/lib/bloc/event_bloc.dart b/lib/bloc/event_bloc.dart deleted file mode 100644 index 45b6844..0000000 --- a/lib/bloc/event_bloc.dart +++ /dev/null @@ -1,235 +0,0 @@ -import 'dart:convert'; - -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/events.dart'; -import 'package:bottle_crm/services/crm_services.dart'; - -class EventBloc { - List _events = []; - Event? _currentEvent; - int? _currentEventIndex; - String? _currentEditEventId = ""; - String _offset = ""; - List _assignedToList = []; - List _contacts = []; - List _recurringDays = []; - Map _currentEditEvent = { - "name": "", - "event_type": "Recurring", - "start_date": null, - "start_time": "", - "end_date": "", - "end_time": "", - "description": "", - "contacts": [], - "teams": [], - "assigned_to": [], - "recurring_day": [], - }; - - Future fetchEvents({filtersData}) async { - try { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - - await CrmService() - .getEvents(queryParams: _copyFiltersData) - .then((response) { - var res = (json.decode(response.body)); - _assignedToList.clear(); - - res['events'].forEach((_event) { - Event event = Event.fromJson(_event); - _events.add(event); - }); - if (res['recurring_days'] != null) { - _recurringDays.clear(); - res['recurring_days'].forEach((_recurringDay) { - _recurringDays.add(_recurringDay[1]); - }); - } - print(_recurringDays); - res['contacts_list'].forEach((_contact) { - Contact contact = Contact.fromJson(_contact); - _contacts.add(contact); - }); - - _offset = res['offset'] != null && res['offset'].toString() != "0" - ? res['offset'].toString() - : ""; - }).catchError((onError) { - print("fetchEvents Error>> $onError"); - }); - } catch (e) {} - } - - Future createEvent() async { - Map? result; - Map _copyCurrentEditEvent = Map.from(_currentEditEvent); - _copyCurrentEditEvent['contacts'] = (_copyCurrentEditEvent['contacts'] - .map((contacts) => contacts.toString())).toList().toString(); - - _copyCurrentEditEvent['teams'] = (_copyCurrentEditEvent['teams'] - .map((teams) => teams.toString())).toList().toString(); - - _copyCurrentEditEvent['assigned_to'] = (_copyCurrentEditEvent['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - - await CrmService() - .createEvent(_copyCurrentEditEvent) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchEvents(); - } - result = res; - }).catchError((onError) { - print('createEvents Error >> $onError'); - result = {"status": "error", "message": "Something went wrong"}; - }); - return result; - } - - Future editEvent() async { - Map? _result; - Map _copyOfCurrentEditEvent = Map.from(_currentEditEvent); - - _copyOfCurrentEditEvent['contacts'] = (_copyOfCurrentEditEvent['contacts'] - .map((contacts) => contacts.toString())).toList().toString(); - - _copyOfCurrentEditEvent['teams'] = (_copyOfCurrentEditEvent['teams'] - .map((teams) => teams.toString())).toList().toString(); - - _copyOfCurrentEditEvent['assigned_to'] = - (_copyOfCurrentEditEvent['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - - await CrmService() - .editEvent(_copyOfCurrentEditEvent, _currentEditEventId) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchEvents(); - } - _result = res; - }).catchError((onError) { - print("editEvent Error >> $onError"); - _result = {"status": "error", "message": "Something went wrong."}; - }); - return _result; - } - - Future deleteEvent(Event event) async { - Map? result; - await CrmService().deleteEvent(event.id).then((response) async { - var res = (json.decode(response.body)); - await fetchEvents(); - result = res; - }).catchError((onError) { - print("deleteEvent Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - updateCurrentEditEvent(Event event) { - _currentEditEventId = event.id.toString(); - - List contacts = []; - List teams = []; - List assignedUsers = []; - - event.contacts!.forEach((contact) { - contacts.add(contact.id); - }); - - event.assignedTo!.forEach((assignedAccount) { - assignedUsers.add(assignedAccount.id); - }); - - event.teams!.forEach((team) { - teams.add(team.id); - }); - - _currentEditEvent = { - "name": "", - "event_type": "Recurring", - "start_date": null, - "start_time": "", - "end_date": "", - "end_time": "", - "description": "", - "contacts": [], - "teams": [], - "assigned_to": [], - "recurring_day": [], - }; - } - - cancelCurrentEditEvent() { - _currentEditEventId = null; - _currentEditEvent = { - "name": "", - "event_type": "Recurring", - "start_date": null, - "start_time": "", - "end_date": "", - "end_time": "", - "description": "", - "contacts": [], - "teams": [], - "assigned_to": [], - "recurring_days": [], - }; - } - - List get events { - return _events; - } - - Event? get currentEvent { - return _currentEvent; - } - - set currentEvent(event) { - _currentEvent = event; - } - - int? get currentEventIndex { - return _currentEventIndex; - } - - set currentEventIndex(index) { - _currentEventIndex = index; - } - - Map get currentEditEvent { - return _currentEditEvent; - } - - set currentEditEvent(currentEditEvent) { - _currentEditEvent = currentEditEvent; - } - - List get recurringDays { - return _recurringDays; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } - - String? get currentEditEventId { - return _currentEditEventId; - } - - set currentEditEventId(id) { - _currentEditEventId = id; - } -} - -final eventBloc = EventBloc(); diff --git a/lib/bloc/lead_bloc.dart b/lib/bloc/lead_bloc.dart deleted file mode 100644 index 3057dbf..0000000 --- a/lib/bloc/lead_bloc.dart +++ /dev/null @@ -1,406 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:bottle_crm/model/lead.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -import 'dashboard_bloc.dart'; - -class LeadBloc { - List _openLeads = []; - List _closedLeads = []; - List _source = []; - List _indrustries = []; - List _status = []; - List? _tags = []; - Lead? _currentLead; - String _currentLeadType = "Open"; - List _users = []; - List _countries = []; - List _countriesList = []; - //List _teams = []; - List _teamsObjForDropdown = []; - List _leadsTitles = []; - List _usersObjForDropdown = []; - String? _currentEditLeadId; - List _filterTags = []; - - Map _currentEditLead = { - "first_name": "", - "last_name": "", - "phone": "", - "account_name": "", - "opportunity_amount": "", - "title": "", - "email": "", - "website": "", - "skype_ID": "", - "description": "", - "assigned_to": [], - "address_line": "", - "street": "", - "postcode": "", - "city": "", - "state": "", - "country": "", - "status": "", - "source": "", - "tags": [], - "industry": "", - }; - String _offset = ""; - - Future fetchLeads({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (filtersData != null) { - _copyFiltersData!['tags'] = _copyFiltersData['tags'].length > 0 - ? jsonEncode( - (_copyFiltersData['tags'].map((id) => id.toString())).toList()) - : ""; - _copyFiltersData['assigned_to'] = - _copyFiltersData['assigned_to'].length > 0 - ? jsonEncode((_copyFiltersData['assigned_to'] - .map((id) => id.toString())).toList()) - : ""; - _copyFiltersData['source'] = _copyFiltersData['source'] != null - ? _copyFiltersData['source'].toString().toLowerCase() - : ""; - _copyFiltersData['status'] = _copyFiltersData['status'] != null - ? _copyFiltersData['status'].toString().toLowerCase() - : ""; - } - await CrmService() - .getLeads(queryParams: _copyFiltersData, offset: _offset) - .then((response) { - var res = json.decode(response.body); - - if (res['open_leads'] != null) { - _leadsTitles.clear(); - // _teams.clear(); - res['open_leads']['open_leads'].forEach((_lead) { - Lead lead = Lead.fromJson(_lead); - _openLeads.add(lead); - }); - - _openLeads.forEach((Lead lead) { - _leadsTitles.add(lead.title); - }); - } - - if (res['close_leads'] != null) { - res['close_leads']['close_leads'].forEach((_lead) { - Lead lead = Lead.fromJson(_lead); - _closedLeads.add(lead); - }); - } - - if (res['source'] != null) { - _source.clear(); - res['source'].forEach((_leadsource) { - _source.add(_leadsource[1]); - }); - } - - if (res['industries'] != null) { - _indrustries.clear(); - res['industries'].forEach((_industries) { - _indrustries.add(_industries[1]); - }); - } - - if (res['status'] != null) { - _status.clear(); - res['status'].forEach((_leadstatus) { - _status.add(_leadstatus[1]); - }); - } - - _filterTags = res['tags'] != null ? res['tags'] : []; - _offset = res['open_leads']['offset'] != null && - res['open_leads']['offset'].toString() != "0" - ? res['open_leads']['offset'].toString() - : res['close_leads']['offset'] != null && - res['close_leads']['offset'].toString() != "0" - ? res['close_leads']['offset'].toString() - : ""; - - if (res['countries'] != null) { - _countries.clear(); - _countriesList = res['countries']; - res['countries'].forEach((country) { - _countries.add(country[1]); - }); - } - }).catchError((onError) { - print('fetchLeads error $onError'); - }); - } - - createLead({File? file}) async { - Map? result; - Map _copyCurrentEditLead = new Map.from(_currentEditLead); - _copyCurrentEditLead['status'] = - _copyCurrentEditLead['status'].toLowerCase(); - _copyCurrentEditLead['source'] = - _copyCurrentEditLead['source'].toLowerCase(); - _copyCurrentEditLead['assigned_to'] = (_copyCurrentEditLead['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - _copyCurrentEditLead['tags'] = jsonEncode(_copyCurrentEditLead['tags']); - _countriesList.forEach((country) { - if (country![1] == _copyCurrentEditLead['country']) { - _copyCurrentEditLead['country'] = country[0]; - } - }); - - await CrmService() - .createLead(_copyCurrentEditLead, file!) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - // await fetchLeads(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }).catchError((onError) { - print('createLead Error >> $onError'); - result = {"status": "error", "message": onError}; - }); - return result; - } - - editLead() async { - Map? result; - Map _copyCurrentEditLead = new Map.from(_currentEditLead); - _copyCurrentEditLead['status'] = - _copyCurrentEditLead['status'].toLowerCase(); - _copyCurrentEditLead['industry'] = - _copyCurrentEditLead['industry'].toLowerCase(); - _copyCurrentEditLead['source'] = - _copyCurrentEditLead['source'].toLowerCase(); - _copyCurrentEditLead['teams'] = (_copyCurrentEditLead['teams'] - .map((team) => team.toString())).toList().toString(); - _copyCurrentEditLead['assigned_to'] = (_copyCurrentEditLead['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - - _copyCurrentEditLead['tags'] = jsonEncode(_copyCurrentEditLead['tags']); - _countriesList.forEach((country) { - if (country[1] == _copyCurrentEditLead['country']) { - _copyCurrentEditLead['country'] = country[0]; - } - }); - await CrmService() - .editLead(_copyCurrentEditLead, _currentEditLeadId) - .then((response) async { - var res = json.decode(response.body); - - if (res["error"] == false) { - await fetchLeads(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }).catchError((onError) { - print('editLead Error >> $onError'); - result = {"status": "error", "message": onError}; - }); - return result; - } - - Future deleteLead(Lead lead) async { - Map? result; - await CrmService().deleteLead(lead.id).then((response) async { - var res = (json.decode(response.body)); - // openLeads.clear(); - // closedLeads.clear(); - await fetchLeads(); - await dashboardBloc.fetchDashboardDetails(); - result = res; - }).catchError((onError) { - print("deleteLead Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - cancelCurrentEditLead() { - _currentEditLead = { - "first_name": "", - "last_name": "", - "phone": "", - "account_name": "", - "skype_ID": "", - "title": "", - "email": "", - "website": "", - "description": "", - "opportunity_amount ": "", - "assigned_to": [], - "address_line": "", - "street": "", - "postcode": "", - "city": "", - "state": "", - "country": "", - "status": "", - "source": "", - "tags": [] - }; - } - - updateCurrentEditLead(Lead editLead) async { - _currentEditLeadId = editLead.id.toString(); - - List teams = []; - List assignedUsers = []; - List? tags = []; - - editLead.teams!.forEach((team) { - teams.add(team.id); - }); - - editLead.assignedTo!.forEach((user) { - assignedUsers.add(user.id); - }); - - for (var tag in editLead.tags!) { - tags.add(tag['name']); - } - - _countriesList.forEach((country) { - if (country[0] == editLead.country) { - editLead.country = country[1]; - } - }); - - _currentEditLead['first_name'] = editLead.firstName; - _currentEditLead['last_name'] = editLead.lastName; - _currentEditLead['phone'] = editLead.phone; - _currentEditLead['account_name'] = editLead.accountName; - _currentEditLead['title'] = editLead.title; - _currentEditLead['email'] = editLead.email; - _currentEditLead['website'] = editLead.website; - _currentEditLead['description'] = editLead.description; - _currentEditLead['teams'] = teams; - // _currentEditLead['users'] = editLead.users; - _currentEditLead['assigned_to'] = assignedUsers; - _currentEditLead['address_line'] = editLead.addressLine; - _currentEditLead['street'] = editLead.street; - _currentEditLead['postcode'] = editLead.postcode; - _currentEditLead['city'] = editLead.city; - _currentEditLead['state'] = editLead.state; - _currentEditLead['country'] = editLead.country; - _currentEditLead['status'] = - editLead.status != null && editLead.status != "" - ? editLead.status!.capitalizeFirstofEach() - : editLead.status; - _currentEditLead['source'] = - editLead.source != null && editLead.source != "" - ? editLead.source!.capitalizeFirstofEach() - : editLead.source; - _currentEditLead['tags'] = tags; - } - - List? get tags { - return _tags; - } - - List get filterTags { - return _filterTags; - } - - Map get currentEditLead { - return _currentEditLead; - } - - set currentEditLead(currentEditLead) { - _currentEditLead = currentEditLead; - } - - String? get currentEditLeadId { - return _currentEditLeadId; - } - - set currentEditLeadId(id) { - _currentEditLeadId = id; - } - - List get openLeads { - return _openLeads; - } - - List get closedLeads { - return _closedLeads; - } - - List get source { - return _source; - } - - List get industry { - return _indrustries; - } - - List get status { - return _status; - } - - List get leadsTitles { - return _leadsTitles; - } - - List get users { - return _users; - } - - Lead? get currentLead { - return _currentLead; - } - - set currentLead(lead) { - _currentLead = lead; - } - - String get currentLeadType { - return _currentLeadType; - } - - set currentLeadType(type) { - _currentLeadType = type; - } - - List get countries { - return _countries; - } - - List? get countriesList { - return _countriesList; - } - - set countriesList(countriesList) { - _countriesList = countriesList; - } - - List get usersObjForDropdown { - return _usersObjForDropdown; - } - - // List get teams { - // return _teams; - // } - - List get teamsObjForDropdown { - return _teamsObjForDropdown; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final leadBloc = LeadBloc(); diff --git a/lib/bloc/opportunity_bloc.dart b/lib/bloc/opportunity_bloc.dart deleted file mode 100644 index 6e3f6b0..0000000 --- a/lib/bloc/opportunity_bloc.dart +++ /dev/null @@ -1,394 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/model/opportunities.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:intl/intl.dart'; - -import 'dashboard_bloc.dart'; - -class OpportunityBloc { - List _opportunities = []; - int? _currentOpportunityIndex; - Opportunity? _currentOpportunity; - String? _currentEditOpportunityId; - - Map _currentEditOpportunity = { - 'name': "", - 'account': "", - 'stage': "", - 'currency': "", - 'amount': "", - 'lead_source': "", - 'probability': 0, - 'contacts': [], - 'due_date': DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())), - 'description': "", - 'assigned_to': [], - 'tags': [], - 'teams': [], - }; - - List? _tags = []; - List _accountsObjforDropDown = []; - List _stageObjforDropDown = []; - List _leadSourceObjforDropDown = []; - List _currencyObjforDropDown = []; - List? _currencyList = []; - List _accountsList = []; - List _filterTags = []; - String _offset = ""; - - Future fetchOpportunities({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (filtersData != null) { - _copyFiltersData!['tags'] = _copyFiltersData['tags'].length > 0 - ? jsonEncode(_copyFiltersData['tags']) - : ""; - if (_copyFiltersData['account'] != null) { - _accountsList.forEach((element) { - if (element[1] == _copyFiltersData['account']) { - _copyFiltersData['account'] = element[0].toString(); - } - }); - } - } - - await CrmService() - .getOpportunities(queryParams: _copyFiltersData, offset: _offset) - .then((response) { - var res = jsonDecode(response.body); - - //_opportunities.clear(); - _accountsObjforDropDown.clear(); - _accountsList.clear(); - _currencyObjforDropDown.clear(); - - res['opportunities'].forEach((_opportunity) { - Opportunity oppor = Opportunity.fromJson(_opportunity); - _opportunities.add(oppor); - }); - - _filterTags = res['tags'] != null ? res['tags'] : []; - _filterTags = res['tags']; - - _offset = res['offset'] != null && res['offset'].toString() != "0" - ? res['offset'].toString() - : ""; - - res['accounts_list'].forEach((_account) { - Account acc = Account.fromJson(_account); - _accountsObjforDropDown.add(acc.name); - _accountsList.add([acc.id, acc.name]); - }); - // _stageObjforDropDown = res['stage']; - //_leadSourceObjforDropDown = res['lead_source']; - if (res['stage'] != null) { - _stageObjforDropDown.clear(); - res['stage'].forEach((_stage) { - _stageObjforDropDown.add(_stage[1]); - }); - } - if (res['lead_source'] != null) { - _leadSourceObjforDropDown.clear(); - res['lead_source'].forEach((_leadsource) { - _leadSourceObjforDropDown.add(_leadsource[1]); - }); - } - res['currency'].forEach((curr) { - _currencyObjforDropDown.add(curr[1]); - }); - - _currencyList = res['currency']; - }).catchError((onError) { - print("fetchOpportunities Error >> $onError"); - }); - } - - Future createOpportunity({File? file}) async { - Map? result; - Map _copyOfCurrentEditOpportunity = new Map.from(_currentEditOpportunity); - _accountsList.forEach((element) { - if (element[1] == _copyOfCurrentEditOpportunity['account']) { - _copyOfCurrentEditOpportunity['account'] = element[0].toString(); - } - }); - if (_copyOfCurrentEditOpportunity['currency'] == "" || - _copyOfCurrentEditOpportunity['currency'] == null) { - _copyOfCurrentEditOpportunity['currency'] = ""; - } else { - _currencyList!.forEach((element) { - if (element[1] == _copyOfCurrentEditOpportunity['currency']) { - _copyOfCurrentEditOpportunity['currency'] = element[0]; - } - }); - } - _copyOfCurrentEditOpportunity['probability'] = - _copyOfCurrentEditOpportunity['probability'].toString(); - - _copyOfCurrentEditOpportunity['teams'] = - (_copyOfCurrentEditOpportunity['teams'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditOpportunity['assigned_to'] = - (_copyOfCurrentEditOpportunity['assigned_to'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditOpportunity['contacts'] = - (_copyOfCurrentEditOpportunity['contacts'].map((e) => e.toString())) - .toList() - .toString(); - - // if (_copyOfCurrentEditOpportunity['due_date'] != "") - // _copyOfCurrentEditOpportunity['due_date'] = - // DateFormat("yyyy-MM-dd") - // .format(DateFormat("dd-MM-yyyy") - // .parse(_copyOfCurrentEditOpportunity['due_date'])); - - _copyOfCurrentEditOpportunity['tags'] = - jsonEncode(_copyOfCurrentEditOpportunity['tags']); - _copyOfCurrentEditOpportunity - .removeWhere((key, value) => value.runtimeType != String); - _copyOfCurrentEditOpportunity - .removeWhere((key, value) => key == "closed_on"); - await CrmService() - .createOpportunity(_copyOfCurrentEditOpportunity, file!) - .then((response) async { - // var res = json.decode(response); # for multipartrequest - var res = json.decode(response.body); - if (res["error"] == false) { - await fetchOpportunities(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }).catchError((onError) { - print("createOpportunity Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - Future editOpportunity() async { - Map? result; - Map _copyOfCurrentEditOpportunity = new Map.from(_currentEditOpportunity); - - _accountsList.forEach((element) { - if (element[1] == _copyOfCurrentEditOpportunity['account']) { - _copyOfCurrentEditOpportunity['account'] = element[0].toString(); - } - }); - - if (_copyOfCurrentEditOpportunity['currency'] == "" || - _copyOfCurrentEditOpportunity['currency'] == null) { - _copyOfCurrentEditOpportunity['currency'] = ""; - } else { - _currencyList!.forEach((element) { - if (element[1] == _copyOfCurrentEditOpportunity['currency']) { - _copyOfCurrentEditOpportunity['currency'] = element[0]; - } - }); - } - _copyOfCurrentEditOpportunity['probability'] = - _copyOfCurrentEditOpportunity['probability'].toString(); - - _copyOfCurrentEditOpportunity['teams'] = - (_copyOfCurrentEditOpportunity['teams'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditOpportunity['assigned_to'] = - (_copyOfCurrentEditOpportunity['assigned_to'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditOpportunity['contacts'] = - (_copyOfCurrentEditOpportunity['contacts'].map((e) => e.toString())) - .toList() - .toString(); - _copyOfCurrentEditOpportunity['tags'] = - jsonEncode(_copyOfCurrentEditOpportunity['tags']); - - _copyOfCurrentEditOpportunity['opportunity_attachment'] = ""; - - if (_copyOfCurrentEditOpportunity['closed_on'] != "") - _copyOfCurrentEditOpportunity['due_date'] = DateFormat("yyyy-MM-dd") - .format(DateFormat("dd-MM-yyyy") - .parse(_copyOfCurrentEditOpportunity['closed_on'])); - - _copyOfCurrentEditOpportunity - .removeWhere((key, value) => value.runtimeType != String); - _copyOfCurrentEditOpportunity - .removeWhere((key, value) => key == "closed_on"); - - await CrmService() - .editOpportunity( - _copyOfCurrentEditOpportunity, _currentEditOpportunityId) - .then((response) async { - var res = json.decode(response.body); - if (res["error"] == false) { - await fetchOpportunities(); - await dashboardBloc.fetchDashboardDetails(); - } - result = res; - }); - // .catchError((onError) { - // print("editOpportunity Error >> $onError"); - // result = {"status": "error", "message": onError}; - // }); - return result; - } - - Future deleteOpportunity(Opportunity opportunity) async { - Map? result; - await CrmService() - .deletefromModule('opportunities', opportunity.id) - .then((response) async { - var res = (json.decode(response.body)); - opportunities.clear(); - await fetchOpportunities(); - await dashboardBloc.fetchDashboardDetails(); - result = res; - }).catchError((onError) { - print("deleteOpportunity Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - cancelCurrentEditOpportunity() { - _currentEditOpportunityId = null; - _currentEditOpportunity = { - 'name': "", - 'account': "", - 'stage': "", - 'currency': "", - 'amount': "", - 'lead_source': "", - 'probability': 0, - 'contacts': [], - 'due_date': DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())), - 'closed_on': "", - 'description': "", - 'assigned_to': [], - 'tags': [], - 'teams': [], - "opportunity_attachment": [] - }; - } - - updateCurrentEditOpportunity(Opportunity editOpportunity) { - List _contacts = []; - List _teams = []; - List _assignedUsers = []; - List _tags = []; - - _currentEditOpportunityId = editOpportunity.id.toString(); - editOpportunity.contacts!.forEach((contact) { - _contacts.add(contact.id); - }); - editOpportunity.assignedTo!.forEach((assignedAccount) { - _assignedUsers.add(assignedAccount.id); - }); - editOpportunity.teams!.forEach((team) { - _teams.add(team.id); - }); - editOpportunity.tags!.forEach((tag) { - _tags.add(tag['name']); - }); - - _currentEditOpportunity = { - 'name': editOpportunity.name, - 'account': editOpportunity.account!.name, - 'stage': editOpportunity.stage, - 'currency': editOpportunity.currency, - 'amount': editOpportunity.amount, - 'lead_source': editOpportunity.leadSource, - 'probability': editOpportunity.probability, - 'contacts': _contacts, - 'closed_on': editOpportunity.closedOn, - 'description': editOpportunity.description, - 'assigned_to': _assignedUsers, - 'tags': _tags, - 'teams': _teams, - 'opportunity_attachment': (editOpportunity.opportunityAttachment!.isEmpty) - ? [] - : editOpportunity.opportunityAttachment![0]['file_path'] - }; - } - - List get opportunities { - return _opportunities; - } - - int? get currentOpportunityIndex { - return _currentOpportunityIndex; - } - - set currentOpportunityIndex(index) { - _currentOpportunityIndex = index; - } - - Opportunity? get currentOpportunity { - return _currentOpportunity; - } - - set currentOpportunity(currOpp) { - _currentOpportunity = currOpp; - } - - String? get currentEditOpportunityId { - return _currentEditOpportunityId; - } - - set currentEditOpportunityId(id) { - _currentEditOpportunityId = id; - } - - Map get currentEditOpportunity { - return _currentEditOpportunity; - } - - set currentEditOpportunity(currEditOpp) { - _currentEditOpportunity = currEditOpp; - } - - List? get tags { - return _tags; - } - - List get filtertags { - return _filterTags; - } - - List get accountsObjforDropDown { - return _accountsObjforDropDown; - } - - List get accountsList { - return _accountsList; - } - - List get stageObjforDropDown { - return _stageObjforDropDown; - } - - List get leadSourceObjforDropDown { - return _leadSourceObjforDropDown; - } - - List get currencyObjforDropDown { - return _currencyObjforDropDown; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final opportunityBloc = OpportunityBloc(); diff --git a/lib/bloc/setting_bloc.dart b/lib/bloc/setting_bloc.dart deleted file mode 100644 index 9061933..0000000 --- a/lib/bloc/setting_bloc.dart +++ /dev/null @@ -1,318 +0,0 @@ -import 'dart:convert'; - -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/domain.dart'; -import 'package:bottle_crm/model/email.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/user.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:intl/intl.dart'; -import 'package:bottle_crm/model/settings.dart'; - -class SettingsBloc { - Map _currentEditSetting = { - 'name': "", - 'last_name': "", - 'email': "", - 'domain': "" - }; - String? _currentEditSettingId; - int _currentSettingsTabIndex = 0; - Settings? _currentSettings; - -//////////////// API SETTINGS ///////////////////////// - List _users = []; - List _usersList = []; - List _apiSettings = []; - List _usersObjForDropDown = []; - String _offset = ""; - - Future fetchApiSettings({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - await CrmService() - .getApiSettings(queryParams: _copyFiltersData, offset: _offset) - .then((response) { - var res = json.decode(response.body); - _usersObjForDropDown.clear(); - _users.clear(); - _apiSettings.clear(); - res['api_settings'].forEach((_settings) { - Settings settings = Settings.fromJson(_settings); - if (_settings['api_settings'] != null && - _settings['api_settings'] != "") - settings.createdOn = DateFormat("dd MMM, yyyy").format( - DateFormat("yyyy-MM-dd").parse(_settings['api_settings'])); - //Settings settings = Settings.fromJson(_settings); - _apiSettings.add(settings); - }); - - res['users'].forEach((_user) { - User user = User.fromJson(_user); - _usersList.add(user); - }); - res['users'].forEach((_user) { - Profile user = Profile.fromJson(_user); - _users.add([user.id, user.firstName]); - _usersObjForDropDown.add(user.firstName); - }); - }); - } - - List get apiSettings { - return _apiSettings; - } - - List get usersList { - return _usersList; - } - - List get users { - return _users; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } - -//////////////// Setting Contacts ///////////////////////// - List _settingsContacts = []; - String _currentSettingsTab = "Contacts"; - Future fetchSettingsContacts({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (_copyFiltersData != null) { - _users.forEach((e) { - if (_copyFiltersData['created_by'] != null) { - if (e[1] == _copyFiltersData['created_by']) { - _copyFiltersData['created_by'] = e[0].toString(); - } - } - }); - } - - await CrmService() - .getSettingsContacts(queryParams: _copyFiltersData) - .then((response) { - var res = json.decode(response.body); - _settingsContacts.clear(); - _usersObjForDropDown.clear(); - _users.clear(); - - res['contacts'].forEach((_contact) { - Contact contact = Contact.fromJson(_contact); - if (_contact['created_on'] != null && _contact['created_on'] != "") - contact.createdOn = DateFormat("dd MMM, yyyy") - .format(DateFormat("yyyy-MM-dd").parse(_contact['created_on'])); - _settingsContacts.add(contact); - }); - res['users'].forEach((_user) { - Profile user = Profile.fromJson(_user); - _users.add([user.id, user.firstName]); - _usersObjForDropDown.add(user.firstName); - }); - }); - } - - Future deleteSettingsContacts(Contact contact) async { - Map? result; - await CrmService() - .deleteSettingsContacts(contact.id) - .then((response) async { - var res = (json.decode(response.body)); - await fetchSettingsContacts(); - result = res; - }).catchError((onError) { - print("deleteSettingsContacts Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - // List get settingsContacts { - // return _settingsContacts; - // } - - // List get users { - // return _users; - // } - - List get userObjForDropDown { - return _usersObjForDropDown; - } - - String get currentSettingsTab { - return _currentSettingsTab; - } - - set currentSettingsTab(tab) { - _currentSettingsTab = tab; - } - - //////////////// BLOCKED DOMAINS ///////////////////////// - - List _blockedDomains = []; - - Future fetchBlockedDomains({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - - await CrmService() - .getBlockedDomains(queryParams: _copyFiltersData) - .then((response) { - var res = json.decode(response.body); - _blockedDomains.clear(); - - res['blocked_domains'].forEach((_domain) { - Domain domain = Domain.fromJson(_domain); - _blockedDomains.add(domain); - }); - }); - } - - Future deleteBlockedDomains(Domain domain) async { - Map? result; - await CrmService().deleteBlockedDomains(domain.id).then((response) async { - var res = (json.decode(response.body)); - await fetchBlockedDomains(); - result = res; - }).catchError((onError) { - print("deleteBlockedDomains Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - List get blockedDomains { - return _blockedDomains; - } - - //////////////// BLOCKED EMAILS ///////////////////////// - - List _blockedEmails = []; - - Future fetchBlockedEmails({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - - await CrmService() - .getBlockedEmails(queryParams: _copyFiltersData) - .then((response) { - var res = json.decode(response.body); - _blockedEmails.clear(); - - res['blocked_emails'].forEach((_email) { - Email email = Email.fromJson(_email); - _blockedEmails.add(email); - }); - }); - } - - Future deleteBlockedEmails(Email email) async { - Map? result; - await CrmService().deleteBlockedEmails(email.id).then((response) async { - var res = (json.decode(response.body)); - await fetchBlockedEmails(); - result = res; - }).catchError((onError) { - print("deleteBlockedEmails Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - List get blockedEmails { - return _blockedEmails; - } - - Future createSetting() async { - Map? _result; - Map _copyOfCurrentEditSetting = Map.from(_currentEditSetting); - await CrmService() - .createSetting(_copyOfCurrentEditSetting) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchBlockedDomains(); - await fetchBlockedEmails(); - await fetchSettingsContacts(); - } - _result = res; - }).catchError((onError) { - print("createUser Error >> $onError"); - _result = {"status": "error", "message": "Something went wrong."}; - }); - return _result; - } - - updateCurrentEditSetting(setting) { - _currentEditSettingId = setting.id.toString(); - - if (_currentSettingsTab == "Contacts") { - _currentEditSetting['name'] = setting.name; - _currentEditSetting['last_name'] = setting.lastName; - _currentEditSetting['email'] = setting.email; - } else if (_currentSettingsTab == "Blocked Domains") { - _currentEditSetting['domain'] = setting.domain; - } else { - _currentEditSetting['email'] = setting.email; - } - } - - resetValues() { - _currentEditSetting['name'] = ""; - _currentEditSetting['last_name'] = ""; - _currentEditSetting['email'] = ""; - _currentEditSetting['domain'] = ""; - } - - Future editSetting() async { - Map? _result; - Map _copyOfCurrentEditSetting = Map.from(_currentEditSetting); - await CrmService() - .editSetting(_copyOfCurrentEditSetting, currentEditSettingId) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchBlockedDomains(); - await fetchBlockedEmails(); - await fetchSettingsContacts(); - } - _result = res; - }).catchError((onError) { - print("createSetting Error >> $onError"); - _result = {"status": "error", "message": "Something went wrong."}; - }); - return _result; - } - - Map get currentEditSetting { - return _currentEditSetting; - } - - String? get currentEditSettingId { - return _currentEditSettingId; - } - - Settings? get currentSettings { - return _currentSettings; - } - - set currentSettings(settings) { - _currentSettings = settings; - } - - int get currentSettingsTabIndex { - return _currentSettingsTabIndex; - } - - set currentSettingsTabIndex(currentSettingsTabIndex) { - _currentSettingsTabIndex = currentSettingsTabIndex; - } -} - -final settingsBloc = SettingsBloc(); diff --git a/lib/bloc/task_bloc.dart b/lib/bloc/task_bloc.dart deleted file mode 100644 index 05375a8..0000000 --- a/lib/bloc/task_bloc.dart +++ /dev/null @@ -1,273 +0,0 @@ -import 'dart:convert'; - -import 'package:bottle_crm/model/task.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'package:intl/intl.dart'; - -import '../model/account.dart'; - -class TaskBloc { - List _tasks = []; - List? _status = []; - List? _priorities = []; - Map? _currentEditTask = { - 'title': "", - 'status': "", - 'priority': "", - 'due_date': "", - 'account': null, - 'contacts': [], - 'teams': [], - 'assigned_to': [] - }; - List _accounts = []; - List _accountsObjforDropDown = []; - String? _currentEditTaskId; - Task? _currentTask; - int? _currentTaskIndex; - String _offset = ""; - - Future fetchTasks({filtersData}) async { - await CrmService() - .getTasks(queryParams: filtersData, offset: _offset) - .then((response) { - var res = json.decode(response.body); - - //_tasks.clear(); - _status!.clear(); - _priorities!.clear(); - if (res['accounts_list'] != null) { - _accounts.clear(); - res['accounts_list'].forEach((_account) { - Account account = Account.fromJson(_account); - _accounts.add(account); - _accountsObjforDropDown.add(account.name); - }); - } - - if (res['tasks'] != null) { - res['tasks'].forEach((_task) { - _accounts.forEach((Account _account) { - if (_task['account'] == _account.id) { - _task['account'] = _account; - } - }); - Task task = Task.fromJson(_task); - _tasks.add(task); - }); - } - - if (res['status'] != null) { - _status!.clear(); - res['status'].forEach((_priority) { - _status!.add(_priority[1]); - }); - } - // if (res['status'] != null) { - // _status.clear(); - // _status = res['status']; - // } - // if (res['priority'] != null) { - // _priorities.clear(); - // _priorities = res['priority']; - // } - if (res['priority'] != null) { - _priorities!.clear(); - res['priority'].forEach((_priority) { - _priorities!.add(_priority[1]); - }); - } - }); - } - - Future createTask() async { - Map? result; - Map _copyCurrentEditTask = Map.from(_currentEditTask!); - _copyCurrentEditTask['contacts'] = (_copyCurrentEditTask['contacts'] - .map((contacts) => contacts.toString())).toList().toString(); - - _copyCurrentEditTask['teams'] = (_copyCurrentEditTask['teams'] - .map((teams) => teams.toString())).toList().toString(); - - _copyCurrentEditTask['assigned_to'] = (_copyCurrentEditTask['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - - if (_copyCurrentEditTask['due_date'] != "") - _copyCurrentEditTask['due_date'] = DateFormat("yyyy-MM-dd").format( - DateFormat("dd-MM-yyyy").parse(_copyCurrentEditTask['due_date'])); - - accounts.forEach((account) { - if (account.name == _copyCurrentEditTask['account']) { - _copyCurrentEditTask['account'] = account.id.toString(); - } - }); - - await CrmService().createTask(_copyCurrentEditTask).then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchTasks(); - } - result = res; - }); - // .catchError((onError) { - // print('createTask Error >> $onError'); - // result = {"status": "error", "message": "Something went wrong"}; - // }); - return result; - } - - Future editTask() async { - Map? _result; - Map _copyOfCurrentEditTask = Map.from(_currentEditTask!); - - _copyOfCurrentEditTask['contacts'] = (_copyOfCurrentEditTask['contacts'] - .map((contacts) => contacts.toString())).toList().toString(); - - _copyOfCurrentEditTask['teams'] = (_copyOfCurrentEditTask['teams'] - .map((teams) => teams.toString())).toList().toString(); - - _copyOfCurrentEditTask['assigned_to'] = - (_copyOfCurrentEditTask['assigned_to'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - - accounts.forEach((account) { - if (account.name == _copyOfCurrentEditTask['account']) { - _copyOfCurrentEditTask['account'] = account.id.toString(); - } - }); - - if (_copyOfCurrentEditTask['due_date'] != "") - _copyOfCurrentEditTask['due_date'] = DateFormat("yyyy-MM-dd").format( - DateFormat("dd-MM-yyyy").parse(_copyOfCurrentEditTask['due_date'])); - - await CrmService() - .editTask(_copyOfCurrentEditTask, _currentEditTaskId) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchTasks(); - } - _result = res; - }).catchError((onError) { - print("editTask Error >> $onError"); - _result = {"status": "error", "message": "Something went wrong."}; - }); - return _result; - } - - Future deleteTask(Task task) async { - Map? result; - await CrmService().deleteTask(task.id).then((response) async { - var res = (json.decode(response.body)); - await fetchTasks(); - result = res; - }).catchError((onError) { - print("deleteTask Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - cancelCurrentEditTask() { - _currentEditTaskId = null; - _currentEditTask = { - 'title': "", - 'status': "", - 'priority': "", - 'due_date': "", - 'account': null, - 'contacts': [], - 'teams': [], - 'assigned_to': [] - }; - } - - updateCurrentEditTask(Task task) { - _currentEditTaskId = task.id.toString(); - - List contacts = []; - List teams = []; - List assignedUsers = []; - - task.contacts!.forEach((contact) { - contacts.add(contact.id); - }); - - task.assignedTo!.forEach((assignedAccount) { - assignedUsers.add(assignedAccount.id); - }); - - task.teams!.forEach((team) { - teams.add(team.id); - }); - - _currentEditTask = { - 'title': task.title, - 'status': task.status, - 'priority': task.priority, - 'due_date': task.dueDate, - 'account': null, - 'contacts': contacts, - 'teams': teams, - 'assigned_to': assignedUsers - }; - } - - List get tasks { - return _tasks; - } - - List? get status { - return _status; - } - - List? get priorities { - return _priorities; - } - - Map? get currentEditTask { - return _currentEditTask; - } - - String? get currentEditTaskId { - return _currentEditTaskId; - } - - set currentEditTaskId(id) { - _currentEditTaskId = id; - } - - Task? get currentTask { - return _currentTask; - } - - set currentTask(task) { - _currentTask = task; - } - - int? get currentTaskIndex { - return _currentTaskIndex; - } - - set currentTaskIndex(index) { - _currentTaskIndex = index; - } - - List get accounts { - return _accounts; - } - - List get accountsObjforDropDown { - return _accountsObjforDropDown; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final taskBloc = TaskBloc(); diff --git a/lib/bloc/team_bloc.dart b/lib/bloc/team_bloc.dart deleted file mode 100644 index b3dfce1..0000000 --- a/lib/bloc/team_bloc.dart +++ /dev/null @@ -1,203 +0,0 @@ -import 'dart:convert'; - -import 'package:bottle_crm/model/team.dart'; -import 'package:bottle_crm/services/crm_services.dart'; - -class TeamBloc { - List _teams = []; - List _users = []; - List _usersObjForDropDown = []; - List _teamsObjForDropdown = []; - Map? _currentEditTeam = { - 'name': "", - 'description': "", - 'assign_users': [], - }; - String? _currentEditTeamId; - Team? _currentTeam; - int? _currentTeamIndex; - String _offset = ""; - - Future fetchTeams({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - if (_copyFiltersData != null) { - _users.forEach((e) { - if (_copyFiltersData['created_by'] != null) { - if (e[1] == _copyFiltersData['created_by']) { - _copyFiltersData['created_by'] = e[0].toString(); - } - } - }); - if (_copyFiltersData['assigne_users'].length != 0) { - _copyFiltersData['assigne_users'] = (_copyFiltersData['assigne_users'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - } - } - - await CrmService().getTeams(queryParams: _copyFiltersData, offset: _offset).then((response) { - var res = json.decode(response.body); - - _teams.clear(); - _users.clear(); - _usersObjForDropDown.clear(); - - res['teams'].forEach((_team) { - Team team = Team.fromJson(_team); - _teams.add(team); - }); - - _teams.forEach((_team) { - Map team = {}; - team['id'] = _team.id; - team['name'] = _team.name!; - _teamsObjForDropdown.add(team); - }); - // res['users'].forEach((_user) { - // Profile user = Profile.fromJson(_user); - // _users.add([user.id, user.firstName]); - // _usersObjForDropDown.add(user.firstName); - // }); - }); - } - - Future createTeam() async { - Map? result; - //print("----"); - // print(_currentEditTeam); - Map _copyCurrentEditTeam = Map.from(_currentEditTeam!); - - _copyCurrentEditTeam['assign_users'] = (_copyCurrentEditTeam['assign_users'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - //print("==="); - // print(_copyCurrentEditTeam); - - - await CrmService().createTeam(_copyCurrentEditTeam).then((response) async { - print(_copyCurrentEditTeam); - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchTeams(); - } - result = res; - }); - - print(result) -; // .catchError((onError) { - // print('createTeam Error >> $onError'); - // result = {"status": "error", "message": "Something went wrong"}; - // }); - return result; - } - - Future editTeam() async { - Map? _result; - Map _copyOfCurrentEditTeam = Map.from(_currentEditTeam!); - - _copyOfCurrentEditTeam['assign_users'] = - (_copyOfCurrentEditTeam['assign_users'] - .map((assignedTo) => assignedTo.toString())).toList().toString(); - await CrmService() - .editTeam(_copyOfCurrentEditTeam, _currentEditTeamId) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchTeams(); - } - _result = res; - }).catchError((onError) { - print("editTeam Error >> $onError"); - _result = {"status": "error", "message": "Something went wrong."}; - }); - return _result; - } - - Future deleteTeam(Team team) async { - Map? result; - await CrmService().deleteTeam(team.id).then((response) async { - var res = (json.decode(response.body)); - await fetchTeams(); - result = res; - }).catchError((onError) { - print("deleteTeam Error >> $onError"); - result = {"status": "error", "message": "Something went wrong."}; - }); - return result; - } - - cancelCurrentEditTeam() { - _currentEditTeamId = null; - _currentEditTeam = { - 'name': "", - 'description': "", - 'assign_users': [], - }; - } - - updateCurrentEditTeam(Team team) { - List _currUsers = []; - _currentEditTeamId = team.id.toString(); - _currentEditTeam = { - 'name': team.name, - 'description': team.description, - }; - team.users!.forEach((element) { - _currUsers.add(element.id); - }); - _currentEditTeam!['assign_users'] = _currUsers; - } - - List get teams { - return _teams; - } - - List get users { - return _users; - } - - List get userObjForDropDown { - return _usersObjForDropDown; - } - - List get teamsObjForDropdown { - return _teamsObjForDropdown; - } - - Map? get currentEditTeam { - return _currentEditTeam; - } - - String? get currentEditTeamId { - return _currentEditTeamId; - } - - set currentEditTeamId(id) { - _currentEditTeamId = id; - } - - Team? get currentTeam { - return _currentTeam; - } - - set currentTeam(team) { - _currentTeam = team; - } - - int? get currentTeamIndex { - return _currentTeamIndex; - } - - set currentTeamIndex(index) { - _currentTeamIndex = index; - } - - String get offset { - return _offset; - } - - set offset(offset) { - _offset = offset; - } -} - -final teamBloc = TeamBloc(); diff --git a/lib/bloc/user_bloc.dart b/lib/bloc/user_bloc.dart deleted file mode 100644 index d46feac..0000000 --- a/lib/bloc/user_bloc.dart +++ /dev/null @@ -1,251 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:bottle_crm/model/user.dart'; -import 'package:bottle_crm/services/crm_services.dart'; - -class UserBloc { - List _activeUsers = []; - List _inActiveUsers = []; - List _usersObjForDropdown = []; - List _statusObjForDropdown = []; - List _rolesObjForDropdown = []; - User? _currentUser; - String _currentUserStatus = "Active"; - int? _currentUserIndex; - String? _currentEditUserId; - Map _currentEditUser = { - 'username': "", - 'role': "USER", - 'status': "Active", - 'profile_pic': "", - 'date_joined': "", - 'email': "", - 'phone': "", - "password": "", - 'first_name': "", - 'last_name': "", - 'has_marketing_access': false, - 'has_sales_access': false, - 'is_active': "True", - 'is_organization_admin': false, - 'description':"", - }; - - Future fetchUsers({filtersData}) async { - Map? _copyFiltersData = - filtersData != null ? new Map.from(filtersData) : null; - - await CrmService().getUsers(queryParams: _copyFiltersData).then((response) { - _activeUsers.clear(); - _inActiveUsers.clear(); - - var res = json.decode(response.body); - if (res['active_users']['active_users'] != null) - res['active_users']['active_users'].forEach((_user) { - User user = User.fromJson(_user); - _activeUsers.add(user); - }); - res['inactive_users']['inactive_users'].forEach((_user) { - User user = User.fromJson(_user); - _activeUsers.add(user); - }); - //_statusObjForDropdown = res['status']; - //_rolesObjForDropdown = res['roles']; - if (res['active_users'] != null) { - // _users.clear(); - // _usersObjForDropdown.clear(); - // res['active_users'].forEach((_user) { - // Profile user = Profile.fromJson(_user); - // _users.add(user); - // }); - _usersObjForDropdown.clear(); - _activeUsers.forEach((_user) { - Map user = {}; - user['id'] = _user.id; - user['name'] = _user.firstName! + ' ' + _user.lastName!; - _usersObjForDropdown.add(user); - }); - } - if (res['roles'] != null) { - _rolesObjForDropdown.clear(); - res['roles'].forEach((_role) { - _rolesObjForDropdown.add(_role[1]); - }); - } - if (res['status'] != null) { - _statusObjForDropdown.clear(); - res['status'].forEach((_status) { - _statusObjForDropdown.add(_status[1]); - }); - } - }).catchError((onError) { - print('fetchUsers Error >> $onError'); - }); - } - - Future createUser({File? file}) async { - Map? _result; - Map _copyOfCurrentEditUser = Map.from(_currentEditUser); - _copyOfCurrentEditUser['has_marketing_access'] = - json.encode(_copyOfCurrentEditUser['has_marketing_access']); - _copyOfCurrentEditUser['has_sales_access'] = - json.encode(_copyOfCurrentEditUser['has_sales_access']); - _copyOfCurrentEditUser['role'] = _copyOfCurrentEditUser['is_admin']; - _copyOfCurrentEditUser['status'] = _copyOfCurrentEditUser['is_active']; - await CrmService() - .createUser(_copyOfCurrentEditUser, file!) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchUsers(); - } - _result = res; - }).catchError((onError) { - print("createUser Error >> $onError"); - _result = {"status": "error", "message": onError}; - }); - return _result; - } - - editUser() async { - Map? _result; - Map _copyOfCurrentEditUser = Map.from(_currentEditUser); - _copyOfCurrentEditUser['has_marketing_access'] = - json.encode(_copyOfCurrentEditUser['has_marketing_access']); - _copyOfCurrentEditUser['has_sales_access'] = - json.encode(_copyOfCurrentEditUser['has_sales_access']); - _copyOfCurrentEditUser['role'] = _copyOfCurrentEditUser['is_admin']; - _copyOfCurrentEditUser['status'] = _copyOfCurrentEditUser['is_active']; - await CrmService() - .editUser(_copyOfCurrentEditUser, _currentEditUserId) - .then((response) async { - var res = json.decode(response.body); - if (res['error'] == false) { - await fetchUsers(); - } - _result = res; - }).catchError((onError) { - print("editUser Error >> $onError"); - _result = {"status": "error", "message": onError}; - }); - return _result; - } - - Future deleteUser(User user) async { - Map? result; - await CrmService().deleteUser(user.id).then((response) async { - var res = (json.decode(response.body)); - await fetchUsers(); - result = res; - }).catchError((onError) { - print("deleteUser Error >> $onError"); - result = {"status": "error", "message": onError}; - }); - return result; - } - - cancelCurrentEditUser() { - _currentEditUserId = null; - _currentEditUser = { - 'username': "", - 'role': "", - 'profile_pic': "", - 'date_joined': "", - 'email': "", - 'phone': "", - "password": "", - 'first_name': "", - 'last_name': "", - 'has_marketing_access': false, - 'has_sales_access': false, - 'is_active': "True", - 'is_organization_admin': "USER", - }; - } - - updateCurrentEditUser(User user) { - _currentEditUserId = user.id.toString(); - - _currentEditUser['username'] = user.firstName; - _currentEditUser['role'] = user.role; - _currentEditUser['profile_pic'] = user.profilePic; - //_currentEditUser['date_joined'] = user.dateOfJoin; - _currentEditUser['email'] = user.email; - _currentEditUser['first_name'] = user.firstName; - _currentEditUser['last_name'] = user.lastName; - _currentEditUser['has_marketing_access'] = user.hasMarktingAccess; - _currentEditUser['has_sales_access'] = user.hasSalesAccess; - - if (user.isActive == true) { - _currentEditUser['is_active'] = "True"; - } else { - _currentEditUser['is_active'] = "False"; - } - if (user.role == "ADMIN") { - _currentEditUser['is_organization_admin'] = true; - _currentEditUser['has_marketing_access'] = true; - _currentEditUser['has_sales_access'] = true; - } else { - _currentEditUser['is_organization_admin'] = false; - } - } - - List get activeUsers { - return _activeUsers; - } - - List get inActiveUsers { - return _inActiveUsers; - } - - List get statusObjForDropdown { - return _statusObjForDropdown; - } - - List get rolesObjForDropdown { - return _rolesObjForDropdown; - } - - User? get currentUser { - return _currentUser; - } - - set currentUser(user) { - _currentUser = user; - } - - String get currentUserStatus { - return _currentUserStatus; - } - - List get usersObjForDropdown { - return _usersObjForDropdown; - } - - set currentUserStatus(status) { - _currentUserStatus = status; - } - - int? get currentUserIndex { - return _currentUserIndex; - } - - set currentUserIndex(index) { - _currentUserIndex = index; - } - - set currentEditUserId(id) { - _currentEditUserId = id; - } - - String? get currentEditUserId { - return _currentEditUserId; - } - - Map get currentEditUser { - return _currentEditUser; - } -} - -final userBloc = UserBloc(); diff --git a/lib/config/api_config.dart b/lib/config/api_config.dart index f244280..c3c4d6f 100644 --- a/lib/config/api_config.dart +++ b/lib/config/api_config.dart @@ -1,41 +1,83 @@ -import 'package:flutter/foundation.dart'; - -class ApiConfig { - // Environment-based API URLs - static const String DEV_API_URL = 'http://192.168.0.106:3001/'; - static const String PROD_API_URL = 'https://api.bottlecrm.io/'; - - // Available APIs for manual switching - static const List AVAILABLE_APIS = [ - DEV_API_URL, - PROD_API_URL, - ]; - - // Current API URL (can be changed at runtime) - static String? _currentApiUrl; - - static void setApiUrl(String url) { - _currentApiUrl = url.endsWith('/') ? url : '$url/'; - } - - static String getApiUrl() { - if (_currentApiUrl != null) { - return _currentApiUrl!; - } - - // Auto-select based on build mode - if (kDebugMode) { - return DEV_API_URL; // Development/Debug builds - } else { - return PROD_API_URL; // Production/Release builds - } - } - - static bool isDebugMode() { - return kDebugMode; - } - - static String getCurrentEnvironment() { - return kDebugMode ? 'Development' : 'Production'; - } -} \ No newline at end of file +import 'package:flutter/foundation.dart'; + +class ApiConfig { + // Base URLs for different environments + static const String _developmentUrl = 'https://b2ad5166b831.ngrok-free.app'; + static const String _productionUrl = 'https://api.bottlecrm.io'; + + // Get base URL based on debug mode + static String get baseUrl => kDebugMode ? _developmentUrl : _productionUrl; + + static String get apiBaseUrl => baseUrl; + + // Authentication endpoints + static String get googleLogin => '$apiBaseUrl/auth/google'; + static String get logout => '$apiBaseUrl/auth/logout'; + + // Contacts endpoints + static String get contacts => '$apiBaseUrl/contacts'; + static String get contactById => '$apiBaseUrl/contacts/{id}'; + static String get contactSearch => '$apiBaseUrl/contacts/search'; + + // Leads endpoints + static String get leads => '$apiBaseUrl/leads'; + static String get leadById => '$apiBaseUrl/leads/{id}'; + static String get leadSearch => '$apiBaseUrl/leads/search'; + static String get leadConvert => '$apiBaseUrl/leads/{id}/convert'; + + // Deals endpoints + static String get deals => '$apiBaseUrl/deals'; + static String get dealById => '$apiBaseUrl/deals/{id}'; + static String get dealSearch => '$apiBaseUrl/deals/search'; + static String get dealStages => '$apiBaseUrl/deals/stages'; + + // Companies endpoints + static String get companies => '$apiBaseUrl/companies'; + static String get companyById => '$apiBaseUrl/companies/{id}'; + static String get companySearch => '$apiBaseUrl/companies/search'; + + // Organizations endpoints + static String get organizations => '$apiBaseUrl/organizations'; + + // Activities endpoints + static String get activities => '$apiBaseUrl/activities'; + static String get activityById => '$apiBaseUrl/activities/{id}'; + static String get activityTypes => '$apiBaseUrl/activities/types'; + + // Tasks endpoints + static String get tasks => '$apiBaseUrl/tasks'; + static String get taskById => '$apiBaseUrl/tasks/{id}'; + static String get taskSearch => '$apiBaseUrl/tasks/search'; + + // Dashboard endpoints + static String get dashboard => '$apiBaseUrl/dashboard'; + + // Settings endpoints + static String get settings => '$apiBaseUrl/settings'; + static String get userSettings => '$apiBaseUrl/settings/user'; + + // File upload endpoints + static String get upload => '$apiBaseUrl/upload'; + static String get uploadAvatar => '$apiBaseUrl/upload/avatar'; + + // Helper method to replace path parameters + static String replacePathParam(String url, String param, String value) { + return url.replaceAll('{$param}', value); + } + + // Request timeout configurations + static const Duration connectTimeout = Duration(seconds: 30); + static const Duration receiveTimeout = Duration(seconds: 30); + static const Duration sendTimeout = Duration(seconds: 30); + + // Common headers + static Map get defaultHeaders => { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + static Map getAuthHeaders(String token) => { + ...defaultHeaders, + 'Authorization': 'Bearer $token', + }; +} diff --git a/lib/main.dart b/lib/main.dart index 13b7a80..eaedfb1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,135 +1,6 @@ -import 'package:bottle_crm/ui/screens/accounts/accounts_list.dart'; -import 'package:bottle_crm/ui/screens/accounts/account_create.dart'; -import 'package:bottle_crm/ui/screens/accounts/account_details.dart'; -import 'package:bottle_crm/ui/screens/authentication/change_password.dart'; -import 'package:bottle_crm/ui/screens/authentication/companies_List.dart'; -import 'package:bottle_crm/ui/screens/modern/authentication/organization_selection_screen.dart'; -import 'package:bottle_crm/ui/screens/authentication/forgot_password.dart'; -import 'package:bottle_crm/ui/screens/authentication/login.dart'; -import 'package:bottle_crm/ui/screens/modern/authentication/login_screen.dart'; -import 'package:bottle_crm/ui/screens/authentication/profile.dart'; -import 'package:bottle_crm/ui/screens/authentication/register.dart'; -import 'package:bottle_crm/ui/screens/cases/case_create.dart'; -import 'package:bottle_crm/ui/screens/cases/case_details.dart'; -import 'package:bottle_crm/ui/screens/cases/cases_list.dart'; -import 'package:bottle_crm/ui/screens/contacts/contact_create.dart'; -import 'package:bottle_crm/ui/screens/contacts/contact_details.dart'; -import 'package:bottle_crm/ui/screens/contacts/contacts_list.dart'; -import 'package:bottle_crm/ui/screens/dashboard/dashboard.dart'; -import 'package:bottle_crm/ui/screens/modern/dashboard_screen.dart'; -import 'package:bottle_crm/ui/screens/documents/documents_list.dart'; -import 'package:bottle_crm/ui/screens/events/event_create.dart'; -import 'package:bottle_crm/ui/screens/events/event_details.dart'; -import 'package:bottle_crm/ui/screens/events/events_list.dart'; -import 'package:bottle_crm/ui/screens/invoices/invoices_list.dart'; -import 'package:bottle_crm/ui/screens/leads/lead_create.dart'; -import 'package:bottle_crm/ui/screens/leads/lead_details.dart'; -import 'package:bottle_crm/ui/screens/leads/leads_list.dart'; -import 'package:bottle_crm/ui/screens/more_options_screen.dart'; -import 'package:bottle_crm/ui/screens/opportunities/opportunitie_create.dart'; -import 'package:bottle_crm/ui/screens/opportunities/opportunitie_details.dart'; -import 'package:bottle_crm/ui/screens/opportunities/opportunities_list.dart'; -import 'package:bottle_crm/ui/screens/settings/settings.dart'; -import 'package:bottle_crm/ui/screens/settings/settings_details.dart'; -import 'package:bottle_crm/ui/screens/settings/settings_userDetails.dart'; -import 'package:bottle_crm/ui/screens/tasks/task_create.dart'; -import 'package:bottle_crm/ui/screens/tasks/task_details.dart'; -import 'package:bottle_crm/ui/screens/tasks/tasks_list.dart'; -import 'package:bottle_crm/ui/screens/teams/team_create.dart'; -import 'package:bottle_crm/ui/screens/teams/team_details.dart'; -import 'package:bottle_crm/ui/screens/teams/teams_list.dart'; -import 'package:bottle_crm/ui/screens/users/user_create.dart'; -import 'package:bottle_crm/ui/screens/users/user_details.dart'; -import 'package:bottle_crm/ui/screens/users/users_list.dart'; import 'package:flutter/material.dart'; -import 'package:firebase_core/firebase_core.dart'; +import 'app.dart'; -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); - runApp(MyApp()); -} - -class MyApp extends StatelessWidget { - //static FirebaseAnalytics _analytics = FirebaseAnalytics.instance; - // static FirebaseAnalyticsObserver getAnalyticsObserver = - // FirebaseAnalyticsObserver(analytics: _analytics); - @override - Widget build(BuildContext context) { - return MaterialApp( - //navigatorObservers: [getAnalyticsObserver], - title: 'bottlecrm', - debugShowCheckedModeBanner: false, - theme: ThemeData( - buttonTheme:ButtonThemeData(buttonColor:Color.fromRGBO(62, 121, 247, 1)), - scaffoldBackgroundColor: Color.fromRGBO(236, 238, 244, 1), - //buttonColor: Color.fromRGBO(62, 121, 247, 1), - primaryColor: Color.fromRGBO(62, 121, 247, 1), - secondaryHeaderColor: Color.fromRGBO(112, 121, 128, 1), - dividerColor: Color.fromRGBO(69, 85, 96, 1)), - home: Login(), - onUnknownRoute: (RouteSettings settings) { - return MaterialPageRoute( - settings: settings, - builder: (BuildContext context) => Scaffold( - body: Container( - alignment: Alignment.center, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('oops! something went wrong.', - style: TextStyle(fontSize: 20.0)) - ], - ), - )), - ); - }, - routes: { - '/login': (BuildContext context) => LoginScreen(), // Modern login - '/login_legacy': (BuildContext context) => Login(), // Legacy login - '/register': (BuildContext context) => Register(), - '/forgot_password': (BuildContext context) => ForgotPassword(), - '/change_password': (BuildContext context) => ChangePassword(), - '/profile': (BuildContext context) => Profile(), - '/dashboard': (BuildContext context) => ModernDashboardScreen(), // Modern dashboard - '/dashboard_legacy': (BuildContext context) => Dashboard(), // Legacy dashboard - '/more_options': (BuildContext context) => MoreOptions(), - '/leads_list': (BuildContext context) => LeadsList(), - '/leads_create': (BuildContext context) => CreateLead(), - '/lead_details': (BuildContext context) => LeadDetails(), - '/accounts_list': (BuildContext context) => AccountsList(), - '/account_create': (BuildContext context) => CreateAccount(), - '/account_details': (BuildContext context) => AccountDetails(), - '/cases_list': (BuildContext context) => CasesList(), - '/case_details': (BuildContext context) => CaseDetails(), - '/case_create': (BuildContext context) => CreateCase(), - '/contacts_list': (BuildContext context) => ContactsList(), - '/contact_create': (BuildContext context) => CreateContact(), - '/contact_details': (BuildContext context) => ContactDetails(), - '/documents_list': (BuildContext context) => DocumentsList(), - '/events_list': (BuildContext context) => EventsList(), - '/event_details': (BuildContext context) => EventDetails(), - '/event_create': (BuildContext context) => CreateEvent(), - '/invoices_list': (BuildContext context) => InvoicesList(), - '/opportunitie_create': (BuildContext context) => CreateOpportunities(), - '/opportunitie_details': (BuildContext context) => - OpportunitiesDetails(), - '/opportunities_list': (BuildContext context) => OpportunitiesList(), - '/tasks_list': (BuildContext context) => TasksList(), - '/task_details': (BuildContext context) => TasskDeails(), - '/task_create': (BuildContext context) => CreateTask(), - '/teams_list': (BuildContext context) => TeamsList(), - '/team_create': (BuildContext context) => CreateTeam(), - '/team_details': (BuildContext context) => TeamkDeails(), - '/users_list': (BuildContext context) => UsersList(), - '/user_create': (BuildContext context) => CreateUser(), - '/user_details': (BuildContext context) => UserDetails(), - '/organization_selection': (BuildContext context) => OrganizationSelectionScreen(), // Modern org selection - '/companies_List': (BuildContext context) => CompaniesList(), // Legacy companies list - '/settings_List': (BuildContext context) => SettingsList(), - '/settings_details': (BuildContext context) => SettingsDeails(), - '/settings_userDetails': (BuildContext context) => SettingsUserDetails(), - }, - ); - } +void main() { + runApp(const BottleCrmApp()); } diff --git a/lib/model/account.dart b/lib/model/account.dart deleted file mode 100644 index 42bf981..0000000 --- a/lib/model/account.dart +++ /dev/null @@ -1,133 +0,0 @@ -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/lead.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:intl/intl.dart'; - -class Account { - int? id; - String? name; - String? email; - String? phone; - String? industry; - String? billingAddressLine; - String? billingStreet; - String? billingCity; - String? billingState; - String? billingPostcode; - String? billingCountry; - String? website; - String? description; - Profile? createdBy; - String? createdOn; - bool? isActive; - List? tags; - String? status; - Lead? lead; - String? contactName; - List? contacts; - List? assignedTo; - List? teams; - - Account( - {this.id, - this.name, - this.email, - this.phone, - this.industry, - this.billingAddressLine, - this.billingStreet, - this.billingCity, - this.billingState, - this.billingPostcode, - this.billingCountry, - this.website, - this.description, - this.createdBy, - this.assignedTo, - this.createdOn, - this.isActive, - this.tags, - this.status, - this.lead, - this.contactName, - this.contacts, - this.teams}); - - Account.fromJson(Map account) { - this.id = account['id'] != null ? account['id'] : 0; - this.name = account['name'] != null ? account['name'] : ""; - this.email = account['email'] != null ? account['email'] : ""; - this.phone = account['phone'] != null ? account['phone'] : ""; - this.industry = account['industry'] != null ? account['industry'] : ""; - this.billingAddressLine = account['billing_address_line'] != null - ? account['billing_address_line'] - : ""; - this.billingStreet = - account['billing_street'] != null ? account['billing_street'] : ""; - this.billingCity = - account['billing_city'] != null ? account['billing_city'] : ""; - this.billingState = - account['billing_state'] != null ? account['billing_state'] : ""; - this.billingPostcode = - account['billing_postcode'] != null ? account['billing_postcode'] : ""; - this.billingCountry = - account['billing_country'] != null ? account['billing_country'] : ""; - this.website = account['website'] != null ? account['website'] : ""; - this.description = - account['description'] != null ? account['description'] : ""; - this.createdBy = account['created_by'] != null - ? Profile.fromJson(account['created_by']) - : Profile(); - this.assignedTo = account['assigned_to'] != null - ? List.from( - account['assigned_to'].map((x) => Profile.fromJson(x))) - : []; - this.createdOn = account['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(account['created_on'])) - : ""; - this.isActive = account['is_active'] != null ? account['is_active'] : false; - this.tags = account['tags'] != null ? account['tags'] : []; - this.status = account['status'] != null ? account['status'] : ""; - this.lead = - account['lead'] != null ? Lead.fromJson(account['lead']) : Lead(); - this.contactName = - account['contact_name'] != null ? account['contact_name'] : ""; - this.contacts = account["contacts"] != null - ? List.from( - account["contacts"].map((x) => Contact.fromJson(x))) - : []; - this.teams = account["teams"] != null - ? List.from(account["teams"].map((x) => Team.fromJson(x))) - : []; - } - - toJson() { - return { - 'id': id, - 'name': name, - 'email': email, - 'phone': phone, - 'industry': industry, - 'billing_address_line': billingAddressLine, - 'billing_street': billingStreet, - 'billing_city': billingCity, - 'billing_state': billingState, - 'billing_postcode': billingPostcode, - 'billing_country': billingCountry, - 'website': website, - 'description': description, - 'created_by': createdBy, - 'assigned_to': assignedTo, - 'created_on': createdOn, - 'is_active': isActive, - 'tags': tags, - 'status': status, - 'lead': lead, - 'contact_name': contactName, - 'contacts': contacts, - 'teams': teams - }; - } -} diff --git a/lib/model/case.dart b/lib/model/case.dart deleted file mode 100644 index d051e17..0000000 --- a/lib/model/case.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:intl/intl.dart'; - -import 'account.dart'; -import 'company.dart'; - -class Case { - int? id; - String? name; - String? status; - String? priority; - String? caseType; - String? closedOn; - String? description; - Profile? createdBy; - String? createdOn; - bool? isActive; - Account? account; - List? contacts; - List? teams; - List? assignedTo; - Company? company; - String? createdOnText; - List? caseAttachment; - - Case( - {this.id, - this.name, - this.status, - this.priority, - this.caseType, - this.closedOn, - this.description, - this.createdBy, - this.createdOn, - this.isActive, - this.account, - this.contacts, - this.teams, - this.assignedTo, - this.company, - this.createdOnText, - this.caseAttachment}); - - Case.fromJson(Map data) { - this.status = data['status'] != null ? data['status'] : ""; - this.priority = data['priority'] != null ? data['priority'] : ""; - this.caseType = data['type_of_case'] != null ? data['type_of_case'] : ""; - this.id = data['id'] != null ? data['id'] : 0; - this.name = data['name'] != null ? data['name'] : ""; - this.account = - data['account'] != null ? Account.fromJson(data['account']) : Account(); - this.contacts = data['contacts'] != null - ? List.from(data["contacts"].map((x) => Contact.fromJson(x))) - : []; - - this.closedOn = data['closed_on'] != null ? data['closed_on'] : ""; - this.description = data['description'] != null ? data['description'] : ""; - this.assignedTo = data['assigned_to'] != null - ? List.from( - data["assigned_to"].map((x) => Profile.fromJson(x))) - : []; - this.createdBy = data['created_by'] != null - ? Profile.fromJson(data['created_by']) - : Profile(); - this.createdOn = data['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(data['created_on'])) - : ""; - this.isActive = data['is_active'] != null ? data['is_active'] : false; - this.teams = data['teams'] != null - ? List.from(data["teams"].map((x) => Team.fromJson(x))) - : []; - this.company = - data['company'] != null ? Company.fromJson(data['company']) : Company(); - this.createdOnText = - data['created_on_arrow'] != null ? data['created_on_arrow'] : ""; - this.caseAttachment = - data['case_attachment'] != null ? data['case_attachment'] : []; - } - - toJson() { - return { - 'id': id, - 'name': name, - 'status': status, - 'priority': priority, - 'type_of_case': caseType, - 'account': account, - 'contacts': contacts, - 'closed_on': closedOn, - 'description': description, - 'assigned_to': assignedTo, - 'created_by': createdBy, - 'created_on': createdOn, - 'is_active': isActive, - 'teams': teams, - 'company': company, - 'created_on_arrow': createdOnText, - 'case_attachment': caseAttachment - }; - } -} diff --git a/lib/model/company.dart b/lib/model/company.dart deleted file mode 100644 index 9e8e7c8..0000000 --- a/lib/model/company.dart +++ /dev/null @@ -1,36 +0,0 @@ -class Company { - int? id; - String? name; - dynamic address; - String? subDomain; - int? userLimit; - String? country; - - Company( - {this.id, - this.name, - this.address, - this.subDomain, - this.userLimit, - this.country}); - - Company.fromJson(Map company) { - this.id = company['id'] != null ? company['id'] : 0; - this.name = company['name'] != null ? company['name'] : ''; - this.address = company['address'] != null ? company['address'] : ''; - this.subDomain = company['sub_domain'] != null ? company['sub_domain'] : ""; - this.userLimit = company['user_limit'] != null ? company['user_limit'] : 0; - this.country = company['country'] != null ? company['country'] : ''; - } - - toJson() { - return { - 'id': id, - 'name': name, - 'address': address, - 'sub_domain': subDomain, - 'user_limit': userLimit, - 'country': country - }; - } -} diff --git a/lib/model/contact.dart b/lib/model/contact.dart deleted file mode 100644 index ccc6990..0000000 --- a/lib/model/contact.dart +++ /dev/null @@ -1,185 +0,0 @@ -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:intl/intl.dart'; - -class Contact { - int? id; - String? salutation; - String? firstName; - String? lastName; - String? primaryEmail; - String? secondaryEmail; - String? primaryMobile; - String? secondaryMobile; - String? dateOfBirth; - String? linkedInUrl; - String? facebookUrl; - String? twitterUserName; - String? organization; - String? department; - bool? doNotCall; - String? title; - Map? address; - String? description; - List? assignedTo; - Profile? createdBy; - String? createdOn; - bool? isActive; - List? teams; - String? createdOnText; - List? teamAndAssignedUsers; - List? assignedUsersNotInTeams; - - Contact( - {this.id, - this.salutation, - this.firstName, - this.lastName, - this.primaryMobile, - this.secondaryMobile, - this.primaryEmail, - this.secondaryEmail, - this.dateOfBirth, - this.linkedInUrl, - this.facebookUrl, - this.twitterUserName, - this.organization, - this.department, - this.doNotCall, - this.title, - this.address, - this.description, - this.assignedTo, - this.createdBy, - this.createdOn, - this.isActive, - this.teams, - this.createdOnText, - this.teamAndAssignedUsers, - this.assignedUsersNotInTeams}); - - Contact.fromJson(Map contact) { - Map address = { - "address_line": "", - "street": "", - "city": "", - "state": "", - "postcode": "", - "country": "" - }; - - address['address_line'] = - contact['address'] != null && contact['address']['address_line'] != null - ? contact['address']['address_line'] - : ""; - address['street'] = - contact['address'] != null && contact['address']['street'] != null - ? ", " + contact['address']['street'] - : ""; - address['city'] = - contact['address'] != null && contact['address']['city'] != null - ? ", " + contact['address']['city'] - : ""; - address['state'] = - contact['address'] != null && contact['address']['state'] != null - ? ", " + contact['address']['state'] - : ""; - address['postcode'] = - contact['address'] != null && contact['address']['postcode'] != null - ? ", " + contact['address']['postcode'].toString() - : ""; - address['country'] = - contact['address'] != null && contact['address']['country'] != null - ? ", " + contact['address']['country'] - : ""; - - this.id = contact['id'] != null ? contact['id'] : 0; - this.salutation = - contact['salutation'] != null ? contact['salutation'] : ''; - this.firstName = contact['first_name'] != null ? contact['first_name'] : ''; - this.lastName = contact['last_name'] != null ? contact['last_name'] : ''; - this.primaryEmail = - contact['primary_email'] != null ? contact['primary_email'] : ""; - this.secondaryEmail = - contact['secondary_email'] != null ? contact['secondary_email'] : ""; - this.primaryMobile = - contact['mobile_number'] != null ? contact['mobile_number'] : ""; - this.secondaryEmail = - contact['secondary_number'] != null ? contact['secondary_number'] : ""; - this.linkedInUrl = - contact['linked_in_url'] != null ? contact['linked_in_url'] : ""; - this.facebookUrl = - contact['facebook_url'] != null ? contact['facebook_url'] : ""; - this.twitterUserName = - contact['twitter_username'] != null ? contact['twitter_username'] : ""; - this.dateOfBirth = - contact['date_of_birth'] != null ? contact['date_of_birth'] : ""; - this.organization = - contact['organization'] != null ? contact['organization'] : ""; - this.department = - contact['department'] != null ? contact['department'] : ""; - this.doNotCall = - contact['do_not_call'] != null ? contact['do_not_call'] : ""; - this.title = contact['title'] != null ? contact['title'] : ""; - this.address = address; - this.description = - contact['description'] != null ? contact['description'] : ""; - this.assignedTo = contact['assigned_to'] != null - ? List.from( - contact['assigned_to'].map((x) => Profile.fromJson(x))) - : []; - this.createdBy = contact['created_by'] != null - ? Profile.fromJson(contact['created_by']) - : Profile(); - this.createdOn = contact['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(contact['created_on'])) - : ""; - this.createdOnText = - contact['created_on_arrow'] != null ? contact['created_on_arrow'] : ""; - this.isActive = contact['is_active'] != null ? contact['is_active'] : false; - this.teams = contact['teams'] != null - ? List.from(contact['teams'].map((x) => Team.fromJson(x))) - : []; - this.teamAndAssignedUsers = contact['get_team_and_assigned_users'] != null - ? List.from(contact['get_team_and_assigned_users'] - .map((x) => Profile.fromJson(x))) - : []; - this.assignedUsersNotInTeams = - contact['get_assigned_users_not_in_teams'] != null - ? List.from(contact['get_assigned_users_not_in_teams'] - .map((x) => Profile.fromJson(x))) - : []; - } - - toJson() { - return { - 'salutation': salutation, - 'id': id, - 'first_name': firstName, - 'last_name': lastName, - 'primary_email': primaryEmail, - 'secondary_email': secondaryEmail, - 'mobile_number': primaryMobile, - 'secondary_number': secondaryMobile, - 'linked_in_url': linkedInUrl, - 'facebook_url': facebookUrl, - 'twitter_username': twitterUserName, - 'organization': organization, - 'department': department, - 'date_of_birth': dateOfBirth, - 'do_not_call': doNotCall, - 'title ': title, - 'address': address, - 'description': description, - 'assigned_to': assignedTo, - 'created_by': createdBy, - 'created_on': createdOn, - 'created_on_arrow': createdOnText, - 'is_active': isActive, - 'teams': teams, - 'get_team_and_assigned_users': teamAndAssignedUsers, - 'get_assigned_users_not_in_teams': assignedUsersNotInTeams - }; - } -} diff --git a/lib/model/document.dart b/lib/model/document.dart deleted file mode 100644 index fa32330..0000000 --- a/lib/model/document.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:bottle_crm/model/company.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; - -class Document { - int? id; - String? title; - String? documentFile; - String? status; - List? sharedTo; - List? teams; - String? createdOn; - Profile? createdBy; - Company? company; - - Document( - {this.id, - this.title, - this.documentFile, - this.status, - this.sharedTo, - this.teams, - this.createdOn, - this.createdBy, - this.company}); - - Document.fromJson(Map document) { - this.id = document['id'] != null ? document['id'] : 0; - this.title = document['title'] != null ? document['title'] : ""; - this.documentFile = - document['document_file'] != null ? document['document_file'] : ""; - this.status = document['status'] != null ? document['status'] : ""; - this.sharedTo = document['shared_to'] != null - ? List.from( - document['shared_to'].map((contact) => Profile.fromJson(contact))) - : []; - this.teams = document["teams"] != null - ? List.from(document["teams"].map((team) => Team.fromJson(team))) - : []; - this.createdOn = document['created_on'] != null - ? document['created_on'] - // ? DateFormat("dd MMM, yyyy 'at' HH:mm") - // .format(DateFormat("yyyy-MM-dd").parse(document['created_on'])) - : ""; - this.createdBy = document['created_by'] != null - ? Profile.fromJson(document['created_by']) - : Profile(); - this.company = document['company'] != null - ? Company.fromJson(document['company']) - : Company(); - } - - toJson() { - return { - "id": id, - "title": title, - "document_file": documentFile, - "status": status, - "shared_to": sharedTo, - "teams": teams, - "created_on": createdOn, - "created_by": createdBy, - "company": company - }; - } -} diff --git a/lib/model/domain.dart b/lib/model/domain.dart deleted file mode 100644 index 44727bb..0000000 --- a/lib/model/domain.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:bottle_crm/model/profile.dart'; -import 'package:intl/intl.dart'; -import 'company.dart'; - -class Domain { - int? id; - String? domain; - String? createdOn; - Profile? createdBy; - Company? company; - - Domain({this.id, this.domain, this.createdOn, this.createdBy, this.company}); - - Domain.fromJson(Map domain) { - this.id = domain['id'] != null ? domain['id'] : 0; - this.domain = domain['domain'] != null ? domain['domain'] : ""; - this.createdOn = domain['created_on'] != null - ? DateFormat("dd MMM, yyyy") - .format(DateFormat("yyyy-MM-dd").parse(domain['created_on'])) - : ""; - this.createdBy = domain['created_by'] != null - ? Profile.fromJson(domain['created_by']) - : Profile(); - this.company = domain['company'] != null - ? Company.fromJson(domain['company']) - : Company(); - } - - toJson() { - return { - "id": id, - "domain": domain, - "created_on": createdOn, - "created_by": createdBy, - "company": company - }; - } -} diff --git a/lib/model/email.dart b/lib/model/email.dart deleted file mode 100644 index ac1533f..0000000 --- a/lib/model/email.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:bottle_crm/model/profile.dart'; -import 'package:intl/intl.dart'; -import 'company.dart'; - -class Email { - int? id; - String? email; - String? createdOn; - Profile? createdBy; - Company? company; - - Email({this.id, this.email, this.createdOn, this.createdBy, this.company}); - - Email.fromJson(Map email) { - this.id = email['id'] != null ? email['id'] : 0; - this.email = email['email'] != null ? email['email'] : ""; - this.createdOn = email['created_on'] != null - ? DateFormat("dd MMM, yyyy") - .format(DateFormat("yyyy-MM-dd").parse(email['created_on'])) - : ""; - this.createdBy = email['created_by'] != null - ? Profile.fromJson(email['created_by']) - : Profile(); - this.company = email['company'] != null - ? Company.fromJson(email['company']) - : Company(); - } - - toJson() { - return { - "id": id, - "email": email, - "created_on": createdOn, - "created_by": createdBy, - "company": company - }; - } -} diff --git a/lib/model/events.dart b/lib/model/events.dart deleted file mode 100644 index e98f9ea..0000000 --- a/lib/model/events.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:intl/intl.dart'; - -class Event { - int? id; - String? name; - String? eventType; - String? startDate; - String? startTime; - String? endDate; - String? endTime; - String? description; - String? dateOfMeeting; - String? createdOn; - Profile? createdBy; - List? contacts; - List? assignedTo; - List? teams; - bool? isActive; - String? status; - - Event( - {this.id, - this.name, - this.eventType, - this.startDate, - this.startTime, - this.endDate, - this.endTime, - this.description, - this.dateOfMeeting, - this.contacts, - this.assignedTo, - this.teams, - this.createdOn, - this.isActive, - this.status, - this.createdBy}); - - Event.fromJson(Map event) { - this.id = event['id'] != null ? event['id'] : 0; - this.name = event['name'] != null ? event['name'] : ""; - this.description = event['description'] != null ? event['description'] : ""; - this.createdBy = event['created_by'] != null - ? Profile.fromJson(event['created_by']) - : Profile(); - this.assignedTo = event['assigned_to'] != null - ? List.from( - event['assigned_to'].map((x) => Profile.fromJson(x))) - : []; - this.createdOn = event['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(event['created_on'])) - : ""; - this.contacts = event["contacts"] != null - ? List.from(event["contacts"].map((x) => Contact.fromJson(x))) - : []; - this.teams = event["teams"] != null - ? List.from(event["teams"].map((x) => Team.fromJson(x))) - : []; - this.isActive = event['is_active'] != null ? event['is_active'] : false; - this.status = event['status'] != null ? event['status'] : ""; - this.eventType = event['event_type'] != null ? event['event_type'] : ""; - this.startDate = event['start_date'] != null ? event['start_date'] : ""; - this.startTime = event['start_time'] != null ? event['start_time'] : ""; - this.endDate = event['end_date'] != null ? event['end_date'] : ""; - this.endTime = event['end_time'] != null ? event['end_time'] : ""; - this.dateOfMeeting= - event['date_of_meeting'] != null ? event['date_of_meeting'] : ""; - } - - toJson() { - return { - 'id': id, - 'name': name, - 'event_type': eventType, - 'status': status, - 'is_active': isActive, - 'start_date': startDate, - 'start_time': startTime, - 'end_date': endDate, - 'end_time': endTime, - 'description': description, - 'date_of_meeting': dateOfMeeting, - 'created_by': createdBy, - 'created_on': createdOn, - 'contacts': contacts, - 'teams': teams, - 'assigned_to': assignedTo, - }; - } -} diff --git a/lib/model/lead.dart b/lib/model/lead.dart deleted file mode 100644 index 694b933..0000000 --- a/lib/model/lead.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:intl/intl.dart'; - -import 'contact.dart'; - -class Lead { - int? id; - String? title; - String? firstName; - String? lastName; - String? email; - String? phone; - String? status; - String? source; - String? addressLine; - String? street; - String? city; - String? state; - String? postcode; - String? country; - String? website; - String? skypeID; - String? description; - List? assignedTo; - String? accountName; - String? opportunityAmount; - Profile? createdBy; - String? createdOn; - bool? isActive; - dynamic enqueryType; - List? tags; - List? contacts; - bool? createdFromSite; - List? teams; - // Company company; - - Lead({ - this.id, - this.title, - this.firstName, - this.lastName, - this.email, - this.phone, - this.status, - this.source, - this.addressLine, - this.street, - this.city, - this.state, - this.postcode, - this.country, - this.website, - this.skypeID, - this.description, - this.assignedTo, - this.accountName, - this.opportunityAmount, - this.createdBy, - this.createdOn, - this.isActive, - this.enqueryType, - this.tags, - this.contacts, - this.createdFromSite, - this.teams, - // this.company, - }); - - factory Lead.fromJson(Map lead) => Lead( - id: lead["id"] != null ? lead["id"] : 0, - title: lead["title"] != null ? lead["title"] : "", - firstName: lead["first_name"] != null ? lead["first_name"] : "", - lastName: lead["last_name"] != null ? lead["last_name"] : "", - email: lead["email"] != null ? lead["email"] : "", - phone: lead["phone"] != null ? lead['phone'] : "", - status: lead["status"] != null ? lead["status"] : "", - source: lead["source"] != null ? lead["source"] : "", - addressLine: lead["address_line"] != null ? lead["address_line"] : "", - street: lead["street"] != null ? lead["street"] : "", - city: lead["city"] != null ? lead["city"] : "", - state: lead["state"] != null ? lead["state"] : "", - postcode: lead["postcode"] != null ? lead["postcode"] : "", - country: lead["country"] != null ? lead["country"] : "", - website: lead["website"] != null ? lead["website"] : "", - skypeID: lead["skype_ID"] != null ? lead["skype_ID"] : "", - description: lead["description"] != null ? lead["description"] : "", - assignedTo: lead["assigned_to"] != null - ? List.from(lead["assigned_to"] - .map((_profile) => Profile.fromJson(_profile))) - : [], - accountName: lead["account_name"] != null ? lead["account_name"] : "", - opportunityAmount: lead["opportunity_amount"] != null - ? lead["opportunity_amount"] - : "", - createdBy: lead["created_by"] != null - ? Profile.fromJson(lead["created_by"]) - : Profile(), - createdOn: lead["created_on"] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(lead['created_on'])) - : "", - isActive: lead["is_active"] != null ? lead["is_active"] : false, - enqueryType: lead["enquery_type"] != null ? lead["enquery_type"] : "", - tags: lead["tags"] != null ? lead["tags"] : [], - contacts: lead["contacts"] != null - ? List.from( - lead["contacts"].map((x) => Contact.fromJson(x))) - : [], - createdFromSite: lead["created_from_site"] != null - ? lead["created_from_site"] - : false, - teams: lead["teams"] != null - ? List.from(lead["teams"].map((x) => Team.fromJson(x))) - : [], - // teams: lead - // company: lead["company"] != null ? lead["company"] : Company(), - ); - - Map toJson() => { - "id": id, - "title": title, - "first_name": firstName, - "last_name": lastName, - "email": email, - "phone": phone, - "status": status, - "source": source, - "address_line": addressLine, - "street": street, - "city": city, - "state": state, - "postcode": postcode, - "country": country, - "website": website, - "skype_ID":skypeID, - "description": description, - "assigned_to": List.from(assignedTo!.map((x) => x.toJson())), - "account_name": accountName, - "opportunity_amount": opportunityAmount, - "created_by": createdBy!.toJson(), - "created_on": createdOn, - "is_active": isActive, - "enquery_type": enqueryType, - "tags": tags, - "contacts": List.from(contacts!.map((x) => x)), - "created_from_site": createdFromSite, - // "teams": List.from(teams.map((x) => x)), - // "company": company, - }; -} diff --git a/lib/model/opportunities.dart b/lib/model/opportunities.dart deleted file mode 100644 index 7d6d8a6..0000000 --- a/lib/model/opportunities.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:intl/intl.dart'; - -import 'account.dart'; -import 'company.dart'; - -class Opportunity { - int? id; - String? name; - Account? account; - String? stage; - String? currency; - String? amount; - String? leadSource; - int? probability; - List? contacts; - Profile? closedBy; - String? closedOn; - String? dueDate; - String? description; - List? assignedTo; - Profile? createdBy; - String? createdOn; - bool? isActive; - List? tags; - List? teams; - Company? company; - String? createdOnText; - List? opportunityAttachment; - - Opportunity( - {this.id, - this.name, - this.account, - this.amount, - this.closedBy, - this.closedOn, - this.dueDate, - this.company, - this.createdBy, - this.createdOn, - this.createdOnText, - this.currency, - this.description, - this.isActive, - this.leadSource, - this.probability, - this.stage, - this.tags, - this.contacts, - this.assignedTo, - this.teams, - this.opportunityAttachment}); - - Opportunity.fromJson(Map opportunity) { - this.id = opportunity['id'] != null ? opportunity['id'] : 0; - this.name = opportunity['name'] != null ? opportunity['name'] : ""; - this.account = opportunity['account'] != null - ? Account.fromJson(opportunity['account']) - : Account(); - this.stage = opportunity['stage'] != null ? opportunity['stage'] : ""; - this.currency = - opportunity['currency'] != null ? opportunity['currency'] : ""; - this.amount = opportunity['amount'] != null ? opportunity['amount'] : ""; - this.leadSource = - opportunity['lead_source'] != null ? opportunity['lead_source'] : ""; - this.probability = - opportunity['probability'] != null ? opportunity['probability'] : 0; - this.contacts = opportunity['contacts'] != null - ? List.from( - opportunity["contacts"].map((x) => Contact.fromJson(x))) - : []; - this.closedBy = opportunity['closed_by'] != null - ? Profile.fromJson(opportunity['closed_by']) - : Profile(); - this.closedOn = - opportunity['closed_on'] != null ? opportunity['closed_on'] : ""; - this.dueDate = - opportunity['due_date'] != null ? opportunity['due_date'] : ""; - this.description = - opportunity['description'] != null ? opportunity['description'] : ""; - this.description = - opportunity['description'] != null ? opportunity['description'] : ""; - this.assignedTo = opportunity['assigned_to'] != null - ? List.from( - opportunity["assigned_to"].map((x) => Profile.fromJson(x))) - : []; - this.createdBy = opportunity['created_by'] != null - ? Profile.fromJson(opportunity['created_by']) - : Profile(); - this.createdOn = opportunity['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(opportunity['created_on'])) - : ""; - this.isActive = - opportunity['is_active'] != null ? opportunity['is_active'] : false; - this.tags = opportunity['tags'] != null ? opportunity['tags'] : []; - this.teams = opportunity['teams'] != null - ? List.from(opportunity["teams"].map((x) => Team.fromJson(x))) - : []; - this.company = opportunity['company'] != null - ? Company.fromJson(opportunity['company']) - : Company(); - this.createdOnText = opportunity['created_on_arrow'] != null - ? opportunity['created_on_arrow'] - : ""; - this.opportunityAttachment = - opportunity['opportunity_attachment'].length != 0 - ? opportunity['opportunity_attachment'] - : []; - } - - toJson() { - return { - 'id': id, - 'name': name, - 'account': account, - 'stage': stage, - 'currency': currency, - 'amount': amount, - 'lead_source': leadSource, - 'probability': probability, - 'contacts': contacts, - 'closed_by': closedBy, - 'closed_on': closedOn, - 'due_date': dueDate, - 'description': description, - 'assigned_to': assignedTo, - 'created_by': createdBy, - 'created_on': createdOn, - 'is_active': isActive, - 'tags': tags, - 'teams': teams, - 'company': company, - 'created_on_arrow': createdOnText, - 'opportunity_attachment': opportunityAttachment - }; - } -} diff --git a/lib/model/organization.dart b/lib/model/organization.dart deleted file mode 100644 index 197c87f..0000000 --- a/lib/model/organization.dart +++ /dev/null @@ -1,17 +0,0 @@ -class Organization { - String? id; - String? name; - String? role; - - Organization({this.id, this.name, this.role}); - - Organization.fromJson(Map data) { - this.id = data['id'] != null ? data['id'].toString() : ""; - this.name = data['name'] != null ? data['name'] : ""; - this.role = data['role'] != null ? data['role'] : ""; - } - - toJson() { - return {'id': id, 'name': name, 'role': role}; - } -} diff --git a/lib/model/profile.dart b/lib/model/profile.dart deleted file mode 100644 index 05cd898..0000000 --- a/lib/model/profile.dart +++ /dev/null @@ -1,98 +0,0 @@ -class Profile { - int? id; - String? email; - String? firstName; - String? lastName; - String? profileUrl; - String? role; - bool? isActive; - bool? isAdmin; - bool? isStaff; - bool? hasSalesAccess; - bool? hasMarketingAccess; - String? dateOfJoin; - - Profile( - {this.id, - this.email, - this.firstName, - this.lastName, - this.profileUrl, - this.role, - this.dateOfJoin, - this.hasMarketingAccess, - this.hasSalesAccess, - this.isActive, - this.isAdmin, - this.isStaff}); - - Profile.fromJson(Map profile) { - // Handle both old format (with user_details) and new format (flat structure) - if (profile['user_details'] != null) { - // Old format - this.id = profile['user_details']['id'] != null - ? profile['user_details']['id'] - : 0; - this.email = profile['user_details']['email'] != null - ? profile['user_details']['email'] - : ""; - this.firstName = profile['user_details']['first_name'] != null - ? profile['user_details']['first_name'] - : ""; - this.lastName = profile['user_details']['last_name'] != null - ? profile['user_details']['last_name'] - : ""; - this.profileUrl = profile['user_details']['profile_pic'] != null - ? profile['user_details']['profile_pic'] - : ""; - } else { - // New format (flat structure from Google login) - this.id = profile['id'] != null ? profile['id'].hashCode : 0; - this.email = profile['email'] != null ? profile['email'] : ""; - - // Parse name into firstName and lastName - if (profile['name'] != null) { - List nameParts = profile['name'].toString().split(' '); - this.firstName = nameParts.isNotEmpty ? nameParts.first : ""; - this.lastName = nameParts.length > 1 ? nameParts.skip(1).join(' ') : ""; - } else { - this.firstName = ""; - this.lastName = ""; - } - - this.profileUrl = profile['profileImage'] != null - ? profile['profileImage'] - : ""; - } - - // Common fields - this.role = profile['role'] != null ? profile['role'] : ""; - this.dateOfJoin = profile['date_of_joining'] != null ? profile['date_of_joining'] : ""; - this.hasMarketingAccess = profile['has_marketing_access'] != null - ? profile['has_marketing_access'] - : false; - this.hasSalesAccess = profile['has_sales_access'] != null - ? profile['has_sales_access'] - : false; - this.isActive = profile['is_active'] != null ? profile['is_active'] : false; - this.isAdmin = profile['is_admin'] != null ? profile['is_admin'] : false; - this.isStaff = profile['is_staff'] != null ? profile['is_staff'] : false; - } - - toJson() { - return { - 'id': id, - 'role': role, - 'profile_pic': profileUrl, - 'date_joined': dateOfJoin, - 'email': email, - 'first_name': firstName, - 'last_name': lastName, - 'has_marketing_access': hasMarketingAccess, - 'has_sales_access': hasSalesAccess, - 'is_active': isActive, - 'is_admin': isAdmin, - 'is_staff': isStaff - }; - } -} diff --git a/lib/model/settings.dart b/lib/model/settings.dart deleted file mode 100644 index d8a995a..0000000 --- a/lib/model/settings.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:bottle_crm/model/lead.dart'; -import 'package:bottle_crm/model/organization.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:intl/intl.dart'; - -class Settings { - int? id; - String? title; - String? website; - Profile? createdBy; - String? createdOn; - List? leadAssignedTo; - List? tags; - Organization? org; - - Settings( - {this.id, - this.title, - this.website, - this.createdBy, - this.createdOn, - this.leadAssignedTo, - this.tags, - this.org}); - - Settings.fromJson(Map settings) { - this.id = settings['id'] != null ? settings['id'] : 0; - this.title = settings['title'] != null ? settings['title'] : ""; - this.website = settings['website'] != null ? settings['website'] : ""; - this.createdBy = settings['created_by'] != null - ? Profile.fromJson(settings['created_by']) - : Profile(); - this.createdOn = settings['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(settings['created_on'])) - : ""; - - this.leadAssignedTo = settings['lead_assigned_to'] != null - ? List.from( - settings['lead_assigned_to'].map((x) => Lead.fromJson(x))) - : []; - this.tags = settings['tags'] != null ? settings['tags'] : []; - this.org = settings['org'] != null - ? Organization.fromJson(settings['org']) - : Organization(); - } - - toJson() { - return { - 'id': id, - 'title': title, - 'website': website, - 'created_by': createdBy, - 'created_on': createdOn, - 'lead_assigned_to': leadAssignedTo, - 'tags': tags, - 'org': org - }; - } -} diff --git a/lib/model/task.dart b/lib/model/task.dart deleted file mode 100644 index db7e0a0..0000000 --- a/lib/model/task.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:bottle_crm/model/company.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:intl/intl.dart'; - -import 'account.dart'; -import 'contact.dart'; -import 'team.dart'; - -class Task { - int? id; - String? title; - String? status; - String? priority; - String? dueDate; - Account? account; - Profile? createdBy; - String? createdOn; - List? contacts; - List? teams; - List? assignedTo; - Company? company; - - Task( - {this.id, - this.title, - this.status, - this.priority, - this.dueDate, - this.account, - this.createdBy, - this.createdOn, - this.contacts, - this.teams, - this.assignedTo, - this.company}); - - Task.fromJson(Map task) { - this.id = task['id'] != null ? task['id'] : 0; - this.title = task['title'] != null ? task['title'] : ""; - this.status = task['status'] != null ? task['status'] : ""; - this.priority = task['priority'] != null ? task['priority'] : ""; - this.dueDate = task['due_date'] != null ? task['due_date'] : ""; - this.account = task['account'] != null ? task['account'] : Account(); - this.createdBy = task['created_by'] != null - ? Profile.fromJson(task['created_by']) - : Profile(); - this.createdOn = task['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(task['created_on'])) - : ""; - this.contacts = task['contacts'] != null - ? List.from(task['contacts'].map((x) => Contact.fromJson(x))) - : []; - this.teams = task['teams'] != null - ? List.from(task['teams'].map((x) => Team.fromJson(x))) - : []; - this.assignedTo = task['assigned_to'] != null - ? List.from( - task['assigned_to'].map((x) => Profile.fromJson(x))) - : []; - this.company = - task['company'] != null ? Company.fromJson(task['company']) : Company(); - } - - toJson() { - return { - 'id': id, - 'title': title, - 'status': status, - 'priority': priority, - 'due_date': dueDate, - 'account': account, - 'created_by': createdBy, - 'created_on': createdOn, - 'contacts': contacts, - 'teams': teams, - 'assigned_to': assignedTo, - 'company': company - }; - } -} diff --git a/lib/model/team.dart b/lib/model/team.dart deleted file mode 100644 index dd1bc6d..0000000 --- a/lib/model/team.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:bottle_crm/model/company.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:intl/intl.dart'; - -class Team { - int? id; - String? name; - String? description; - List? users; - String? createdOn; - Profile? createdBy; - int? createdById; - Company? company; - int? companyId; - String? createdOnText; - - Team( - {this.id, - this.name, - this.description, - this.users, - this.createdOn, - this.createdBy, - this.createdById, - this.company, - this.companyId, - this.createdOnText}); - - Team.fromJson(Map team) { - this.id = team['id'] != null ? team['id'] : 0; - this.name = team['name'] != null ? team['name'] : ""; - this.description = team['description'] != null ? team['description'] : ""; - this.users = team['users'] != null - ? List.from(team['users'].map((x) => Profile.fromJson(x))) - : []; - this.createdOn = team['created_on'] != null - ? DateFormat("dd-MM-yyyy") - .format(DateFormat("yyyy-MM-dd").parse(team['created_on'])) - : ""; - this.createdBy = team['created_by'] != null - ? Profile.fromJson(team['created_by']) - : Profile(); - this.createdById = - team['created_by'] != null ? team['created_by']['id'] : 0; - this.company = - team['company'] != null ? Company.fromJson(team['company']) : Company(); - this.companyId = team['company'] != null ? team['company']['id'] : 0; - this.createdOnText = - team['created_on_arrow'] != null ? team['created_on_arrow'] : ""; - } - - toJson() { - return { - 'id': id, - 'name': name, - 'description': description, - 'users': users, - 'created_on': createdOn, - 'created_by': createdBy, - 'created_by_id': createdById, - 'company': company, - 'company_id': companyId, - 'created_on_arrow': createdOnText, - }; - } - - void forEach(Null Function(dynamic _user) param0) {} -} diff --git a/lib/model/user.dart b/lib/model/user.dart deleted file mode 100644 index 8333d85..0000000 --- a/lib/model/user.dart +++ /dev/null @@ -1,121 +0,0 @@ -class User { - int? id; - String? firstName; - String? lastName; - String? role; - String? email; - String? alternateEmail; - String? phone; - String? alternatePhone; - String? skypeID; - String? profilePic; - bool? hasSalesAccess; - bool? hasMarktingAccess; - String? isMarketingAdmin; - bool? isActive; - String? status; - String? adressLine; - String? street; - String? city; - String? state; - String? pincode; - String? country; - String? description; - - User({ - this.id, - this.firstName, - this.lastName, - this.role, - this.phone, - this.alternatePhone, - this.email, - this.alternateEmail, - this.skypeID, - this.profilePic, - this.hasSalesAccess, - this.hasMarktingAccess, - this.isMarketingAdmin, - this.isActive, - this.status, - this.adressLine, - this.street, - this.city, - this.state, - this.pincode, - this.country, - this.description, - }); - - User.fromJson(Map user) { - this.id = user['id'] != null ? user['id'] : 0; - this.firstName = user['user_details']['first_name'] != null - ? user['user_details']['first_name'] - : ""; - this.lastName = user['user_details']['last_name'] != null - ? user['user_details']['last_name'] - : ""; - this.role = user['role'] != null ? user['role'] : ""; - this.email = user['user_details']['email'] != null - ? user['user_details']['email'] - : ""; - this.alternateEmail = user['user_details']['alternate_email'] != null - ? user['user_details']['alternate_email'] - : ""; - this.phone = user['phone'] != null ? user['phone'] : ""; - this.alternatePhone = - user['alternate_phone'] != null ? user['alternate_phone'] : ""; - this.skypeID = user['user_details']['skype_ID'] != null - ? user['user_details']['skype_ID'] - : ""; - this.profilePic = user['user_details']['profile_pic '] != null - ? user['user_details']['profile_pic '] - : ""; - this.hasSalesAccess = - user['has_sales_access'] != null ? user['has_sales_access'] : ""; - this.hasMarktingAccess = user['has_marketing_access'] != null - ? user['has_marketing_access'] - : ""; - this.isMarketingAdmin = user['is_organization_admin'] != null - ? user['is_organization_admin'] - : ""; - this.description = user['user_details']['description'] != null - ? user['user_details']['description'] - : ""; - this.isActive = user['is_active'] != null ? user['is_active'] : false; - this.status = user['status'] != null ? user['status'] : ""; - this.adressLine = user['address_line'] != null ? user['address_line'] : ""; - this.street = user['street'] != null ? user['street'] : ""; - this.city = user['city'] != null ? user['city'] : ""; - this.state = user['state'] != null ? user['state'] : ""; - this.pincode = user['pincode'] != null ? user['pincode'] : ""; - this.country = user['country'] != null ? user['country'] : ""; - } - - toJson() { - return { - 'id': id, - 'first_name': firstName, - 'last_name': lastName, - 'role': role, - 'email': email, - 'alternate_email': alternateEmail, - 'phone': phone, - 'alternate_phone': alternatePhone, - 'profile_pic': profilePic, - 'skype_ID': skypeID, - 'has_sales_access ': hasSalesAccess, - 'has_marketing_access': hasMarktingAccess, - 'is_organization_admin': isMarketingAdmin, - 'is_active':isActive, - 'status':status, - 'description': description, - 'address_line': adressLine, - 'street': street, - 'state': state, - 'city': city, - 'pincode': pincode, - 'country': country, - }; - } -} diff --git a/lib/models/api_models.dart b/lib/models/api_models.dart new file mode 100644 index 0000000..ec73f24 --- /dev/null +++ b/lib/models/api_models.dart @@ -0,0 +1,1541 @@ +// Base model classes for API responses + +class ApiResponse { + final bool success; + final T? data; + final String? message; + final int statusCode; + final Map? errors; + final Pagination? pagination; + + ApiResponse({ + required this.success, + this.data, + this.message, + required this.statusCode, + this.errors, + this.pagination, + }); + + factory ApiResponse.fromJson( + Map json, + T Function(dynamic)? fromJsonT, + ) { + return ApiResponse( + success: json['success'] ?? false, + data: json['data'] != null && fromJsonT != null + ? fromJsonT(json['data']) + : json['data'], + message: json['message'], + statusCode: json['status_code'] ?? 200, + errors: json['errors'], + pagination: json['pagination'] != null + ? Pagination.fromJson(json['pagination']) + : null, + ); + } +} + +class Pagination { + final int page; + final int limit; + final int total; + final int? totalPages; + final bool hasNext; + final bool hasPrev; + + Pagination({ + required this.page, + required this.limit, + required this.total, + this.totalPages, + required this.hasNext, + required this.hasPrev, + }); + + bool get hasPrevious => hasPrev; + int get pages => totalPages ?? 1; + + factory Pagination.fromJson(Map json) { + final totalPagesValue = json['totalPages'] ?? json['pages']; + int? totalPagesInt; + + if (totalPagesValue is int) { + totalPagesInt = totalPagesValue; + } else if (totalPagesValue is String && int.tryParse(totalPagesValue) != null) { + totalPagesInt = int.parse(totalPagesValue); + } + + return Pagination( + page: (json['page'] is int) ? json['page'] : int.tryParse(json['page']?.toString() ?? '1') ?? 1, + limit: (json['limit'] is int) ? json['limit'] : int.tryParse(json['limit']?.toString() ?? '10') ?? 10, + total: (json['total'] is int) ? json['total'] : int.tryParse(json['total']?.toString() ?? '0') ?? 0, + totalPages: totalPagesInt, + hasNext: json['hasNext'] is bool ? json['hasNext'] : (json['hasNext']?.toString().toLowerCase() == 'true'), + hasPrev: json['hasPrev'] is bool ? json['hasPrev'] : (json['hasPrev']?.toString().toLowerCase() == 'true'), + ); + } + + Map toJson() { + return { + 'page': page, + 'limit': limit, + 'total': total, + 'totalPages': totalPages, + 'hasNext': hasNext, + 'hasPrev': hasPrev, + }; + } +} + +// Contact model +class Contact { + final String id; + final String firstName; + final String lastName; + final String? email; + final String? phone; + final String? title; + final String? department; + final String? street; + final String? city; + final String? state; + final String? postalCode; + final String? country; + final double? latitude; + final double? longitude; + final String? description; + final DateTime createdAt; + final DateTime updatedAt; + final String? ownerId; + final String organizationId; + final ContactOwner? owner; + final ContactOrganization? organization; + final List? relatedAccounts; + + Contact({ + required this.id, + required this.firstName, + required this.lastName, + this.email, + this.phone, + this.title, + this.department, + this.street, + this.city, + this.state, + this.postalCode, + this.country, + this.latitude, + this.longitude, + this.description, + required this.createdAt, + required this.updatedAt, + this.ownerId, + required this.organizationId, + this.owner, + this.organization, + this.relatedAccounts, + }); + + String get fullName => '$firstName $lastName'; + + String get fullAddress { + final parts = [ + street, + city, + state, + postalCode, + country, + ].where((part) => part != null && part.isNotEmpty).toList(); + return parts.join(', '); + } + + factory Contact.fromJson(Map json) { + return Contact( + id: json['id'] ?? '', + firstName: json['firstName'] ?? '', + lastName: json['lastName'] ?? '', + email: json['email'], + phone: json['phone'], + title: json['title'], + department: json['department'], + street: json['street'], + city: json['city'], + state: json['state'], + postalCode: json['postalCode'], + country: json['country'], + latitude: json['latitude']?.toDouble(), + longitude: json['longitude']?.toDouble(), + description: json['description'], + createdAt: DateTime.parse( + json['createdAt'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updatedAt'] ?? DateTime.now().toIso8601String(), + ), + ownerId: json['ownerId'], + organizationId: json['organizationId'] ?? '', + owner: json['owner'] != null + ? ContactOwner.fromJson(json['owner']) + : null, + organization: json['organization'] != null + ? ContactOrganization.fromJson(json['organization']) + : null, + relatedAccounts: json['relatedAccounts'] != null + ? (json['relatedAccounts'] as List) + .map( + (account) => + RelatedAccount.fromJson(account as Map), + ) + .toList() + : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'firstName': firstName, + 'lastName': lastName, + 'email': email, + 'phone': phone, + 'title': title, + 'department': department, + 'street': street, + 'city': city, + 'state': state, + 'postalCode': postalCode, + 'country': country, + 'latitude': latitude, + 'longitude': longitude, + 'description': description, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'ownerId': ownerId, + 'organizationId': organizationId, + 'owner': owner?.toJson(), + 'organization': organization?.toJson(), + 'relatedAccounts': relatedAccounts + ?.map((account) => account.toJson()) + .toList(), + }; + } +} + +class ContactOwner { + final String id; + final String name; + final String email; + + ContactOwner({required this.id, required this.name, required this.email}); + + String get fullName => name; + + factory ContactOwner.fromJson(Map json) { + return ContactOwner( + id: json['id'] ?? '', + name: json['name'] ?? '', + email: json['email'] ?? '', + ); + } + + Map toJson() { + return {'id': id, 'name': name, 'email': email}; + } +} + +class ContactOrganization { + final String id; + final String name; + + ContactOrganization({required this.id, required this.name}); + + factory ContactOrganization.fromJson(Map json) { + return ContactOrganization(id: json['id'] ?? '', name: json['name'] ?? ''); + } + + Map toJson() { + return {'id': id, 'name': name}; + } +} + +class RelatedAccount { + final String id; + final String role; + final bool isPrimary; + final DateTime startDate; + final DateTime? endDate; + final String? description; + final DateTime createdAt; + final DateTime updatedAt; + final Account account; + + RelatedAccount({ + required this.id, + required this.role, + required this.isPrimary, + required this.startDate, + this.endDate, + this.description, + required this.createdAt, + required this.updatedAt, + required this.account, + }); + + factory RelatedAccount.fromJson(Map json) { + return RelatedAccount( + id: json['id'] ?? '', + role: json['role'] ?? '', + isPrimary: json['isPrimary'] ?? false, + startDate: DateTime.parse( + json['startDate'] ?? DateTime.now().toIso8601String(), + ), + endDate: json['endDate'] != null ? DateTime.parse(json['endDate']) : null, + description: json['description'], + createdAt: DateTime.parse( + json['createdAt'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updatedAt'] ?? DateTime.now().toIso8601String(), + ), + account: Account.fromJson(json['account'] ?? {}), + ); + } + + Map toJson() { + return { + 'id': id, + 'role': role, + 'isPrimary': isPrimary, + 'startDate': startDate.toIso8601String(), + 'endDate': endDate?.toIso8601String(), + 'description': description, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'account': account.toJson(), + }; + } +} + +class Account { + final String id; + final String name; + final String type; + final String? website; + final String? phone; + + Account({ + required this.id, + required this.name, + required this.type, + this.website, + this.phone, + }); + + factory Account.fromJson(Map json) { + return Account( + id: json['id'] ?? '', + name: json['name'] ?? '', + type: json['type'] ?? '', + website: json['website'], + phone: json['phone'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'type': type, + 'website': website, + 'phone': phone, + }; + } +} + +// Contacts response wrapper for API +class ContactsResponse { + final List contacts; + final Pagination? pagination; + + ContactsResponse({required this.contacts, this.pagination}); + + factory ContactsResponse.fromJson(Map json) { + return ContactsResponse( + contacts: + (json['contacts'] as List?) + ?.map( + (contactJson) => + Contact.fromJson(contactJson as Map), + ) + .toList() ?? + [], + pagination: json['pagination'] != null + ? Pagination.fromJson(json['pagination']) + : null, + ); + } +} + +// Lead model +class Lead { + final String id; + final String firstName; + final String lastName; + final String? email; + final String? phone; + final String? company; + final String? title; + final String status; + final String leadSource; + final String? industry; + final String? rating; + final String? description; + final DateTime createdAt; + final DateTime updatedAt; + final String? ownerId; + final String organizationId; + final bool isConverted; + final DateTime? convertedAt; + final String? convertedAccountId; + final String? convertedContactId; + final String? convertedOpportunityId; + final String? contactId; + final LeadOwner? owner; + + Lead({ + required this.id, + required this.firstName, + required this.lastName, + this.email, + this.phone, + this.company, + this.title, + required this.status, + required this.leadSource, + this.industry, + this.rating, + this.description, + required this.createdAt, + required this.updatedAt, + this.ownerId, + required this.organizationId, + required this.isConverted, + this.convertedAt, + this.convertedAccountId, + this.convertedContactId, + this.convertedOpportunityId, + this.contactId, + this.owner, + }); + + String get fullName => '$firstName $lastName'; + + factory Lead.fromJson(Map json) { + return Lead( + id: json['id'] ?? '', + firstName: json['firstName'] ?? '', + lastName: json['lastName'] ?? '', + email: json['email'], + phone: json['phone'], + company: json['company'], + title: json['title'], + status: json['status'] ?? 'NEW', + leadSource: json['leadSource'] ?? '', + industry: json['industry'], + rating: json['rating'], + description: json['description'], + createdAt: DateTime.parse( + json['createdAt'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updatedAt'] ?? DateTime.now().toIso8601String(), + ), + ownerId: json['ownerId'], + organizationId: json['organizationId'] ?? '', + isConverted: json['isConverted'] ?? false, + convertedAt: json['convertedAt'] != null + ? DateTime.parse(json['convertedAt']) + : null, + convertedAccountId: json['convertedAccountId'], + convertedContactId: json['convertedContactId'], + convertedOpportunityId: json['convertedOpportunityId'], + contactId: json['contactId'], + owner: json['owner'] != null ? LeadOwner.fromJson(json['owner']) : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'firstName': firstName, + 'lastName': lastName, + 'email': email, + 'phone': phone, + 'company': company, + 'title': title, + 'status': status, + 'leadSource': leadSource, + 'industry': industry, + 'rating': rating, + 'description': description, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'ownerId': ownerId, + 'organizationId': organizationId, + 'isConverted': isConverted, + 'convertedAt': convertedAt?.toIso8601String(), + 'convertedAccountId': convertedAccountId, + 'convertedContactId': convertedContactId, + 'convertedOpportunityId': convertedOpportunityId, + 'contactId': contactId, + 'owner': owner?.toJson(), + }; + } +} + +class LeadOwner { + final String id; + final String name; + final String email; + + LeadOwner({required this.id, required this.name, required this.email}); + + String get fullName => name; + + factory LeadOwner.fromJson(Map json) { + return LeadOwner( + id: json['id'] ?? '', + name: json['name'] ?? '', + email: json['email'] ?? '', + ); + } + + Map toJson() { + return {'id': id, 'name': name, 'email': email}; + } +} + +// Lead response wrapper for API +class LeadsResponse { + final List leads; + final Pagination pagination; + + LeadsResponse({required this.leads, required this.pagination}); + + factory LeadsResponse.fromJson(Map json) { + return LeadsResponse( + leads: + (json['leads'] as List?) + ?.map( + (leadJson) => Lead.fromJson(leadJson as Map), + ) + .toList() ?? + [], + pagination: Pagination.fromJson(json['pagination'] ?? {}), + ); + } +} + +// Deal model +class Deal { + final String id; + final String title; + final String? description; + final double value; + final String currency; + final DealStage stage; + final String? contactId; + final String? companyId; + final DateTime? expectedCloseDate; + final double probability; + final DateTime createdAt; + final DateTime updatedAt; + final Map? customFields; + + Deal({ + required this.id, + required this.title, + this.description, + required this.value, + required this.currency, + required this.stage, + this.contactId, + this.companyId, + this.expectedCloseDate, + required this.probability, + required this.createdAt, + required this.updatedAt, + this.customFields, + }); + + factory Deal.fromJson(Map json) { + return Deal( + id: json['id'] ?? '', + title: json['title'] ?? '', + description: json['description'], + value: (json['value'] ?? 0).toDouble(), + currency: json['currency'] ?? 'USD', + stage: DealStage.fromString(json['stage'] ?? 'prospect'), + contactId: json['contact_id'], + companyId: json['company_id'], + expectedCloseDate: json['expected_close_date'] != null + ? DateTime.parse(json['expected_close_date']) + : null, + probability: (json['probability'] ?? 0).toDouble(), + createdAt: DateTime.parse( + json['created_at'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updated_at'] ?? DateTime.now().toIso8601String(), + ), + customFields: json['custom_fields'], + ); + } + + Map toJson() { + return { + 'id': id, + 'title': title, + 'description': description, + 'value': value, + 'currency': currency, + 'stage': stage.value, + 'contact_id': contactId, + 'company_id': companyId, + 'expected_close_date': expectedCloseDate?.toIso8601String(), + 'probability': probability, + 'created_at': createdAt.toIso8601String(), + 'updated_at': updatedAt.toIso8601String(), + 'custom_fields': customFields, + }; + } +} + +enum DealStage { + prospect('prospect'), + qualified('qualified'), + proposal('proposal'), + negotiation('negotiation'), + closed('closed'), + won('won'), + lost('lost'); + + const DealStage(this.value); + final String value; + + static DealStage fromString(String value) { + return DealStage.values.firstWhere( + (stage) => stage.value == value, + orElse: () => DealStage.prospect, + ); + } +} + +// Company model +class Company { + final String id; + final String name; + final String? website; + final String? industry; + final String? phone; + final String? email; + final Address? address; + final int? employeeCount; + final double? revenue; + final DateTime createdAt; + final DateTime updatedAt; + final Map? customFields; + + Company({ + required this.id, + required this.name, + this.website, + this.industry, + this.phone, + this.email, + this.address, + this.employeeCount, + this.revenue, + required this.createdAt, + required this.updatedAt, + this.customFields, + }); + + factory Company.fromJson(Map json) { + return Company( + id: json['id'] ?? '', + name: json['name'] ?? '', + website: json['website'], + industry: json['industry'], + phone: json['phone'], + email: json['email'], + address: json['address'] != null + ? Address.fromJson(json['address']) + : null, + employeeCount: json['employee_count'], + revenue: json['revenue']?.toDouble(), + createdAt: DateTime.parse( + json['created_at'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updated_at'] ?? DateTime.now().toIso8601String(), + ), + customFields: json['custom_fields'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'website': website, + 'industry': industry, + 'phone': phone, + 'email': email, + 'address': address?.toJson(), + 'employee_count': employeeCount, + 'revenue': revenue, + 'created_at': createdAt.toIso8601String(), + 'updated_at': updatedAt.toIso8601String(), + 'custom_fields': customFields, + }; + } +} + +// Address model +class Address { + final String? street; + final String? city; + final String? state; + final String? zipCode; + final String? country; + + Address({this.street, this.city, this.state, this.zipCode, this.country}); + + factory Address.fromJson(Map json) { + return Address( + street: json['street'], + city: json['city'], + state: json['state'], + zipCode: json['zip_code'], + country: json['country'], + ); + } + + Map toJson() { + return { + 'street': street, + 'city': city, + 'state': state, + 'zip_code': zipCode, + 'country': country, + }; + } + + String get fullAddress { + final parts = [ + street, + city, + state, + zipCode, + country, + ].where((part) => part != null && part.isNotEmpty).toList(); + return parts.join(', '); + } +} + +// Activity model +class Activity { + final String id; + final String type; + final String title; + final String? description; + final String? contactId; + final String? dealId; + final String? companyId; + final DateTime scheduledAt; + final DateTime? completedAt; + final ActivityStatus status; + final DateTime createdAt; + final DateTime updatedAt; + + Activity({ + required this.id, + required this.type, + required this.title, + this.description, + this.contactId, + this.dealId, + this.companyId, + required this.scheduledAt, + this.completedAt, + required this.status, + required this.createdAt, + required this.updatedAt, + }); + + factory Activity.fromJson(Map json) { + return Activity( + id: json['id'] ?? '', + type: json['type'] ?? '', + title: json['title'] ?? '', + description: json['description'], + contactId: json['contact_id'], + dealId: json['deal_id'], + companyId: json['company_id'], + scheduledAt: DateTime.parse( + json['scheduled_at'] ?? DateTime.now().toIso8601String(), + ), + completedAt: json['completed_at'] != null + ? DateTime.parse(json['completed_at']) + : null, + status: ActivityStatus.fromString(json['status'] ?? 'pending'), + createdAt: DateTime.parse( + json['created_at'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updated_at'] ?? DateTime.now().toIso8601String(), + ), + ); + } + + Map toJson() { + return { + 'id': id, + 'type': type, + 'title': title, + 'description': description, + 'contact_id': contactId, + 'deal_id': dealId, + 'company_id': companyId, + 'scheduled_at': scheduledAt.toIso8601String(), + 'completed_at': completedAt?.toIso8601String(), + 'status': status.value, + 'created_at': createdAt.toIso8601String(), + 'updated_at': updatedAt.toIso8601String(), + }; + } +} + +enum ActivityStatus { + pending('pending'), + completed('completed'), + cancelled('cancelled'), + overdue('overdue'); + + const ActivityStatus(this.value); + final String value; + + static ActivityStatus fromString(String value) { + return ActivityStatus.values.firstWhere( + (status) => status.value == value, + orElse: () => ActivityStatus.pending, + ); + } +} + +// Dashboard metrics model +class DashboardMetrics { + final int totalLeads; + final int totalOpportunities; + final int totalAccounts; + final int totalContacts; + final int pendingTasks; + final double opportunityRevenue; + + DashboardMetrics({ + required this.totalLeads, + required this.totalOpportunities, + required this.totalAccounts, + required this.totalContacts, + required this.pendingTasks, + required this.opportunityRevenue, + }); + + factory DashboardMetrics.fromJson(Map json) { + final metrics = json['metrics'] ?? {}; + return DashboardMetrics( + totalLeads: metrics['totalLeads'] ?? 0, + totalOpportunities: metrics['totalOpportunities'] ?? 0, + totalAccounts: metrics['totalAccounts'] ?? 0, + totalContacts: metrics['totalContacts'] ?? 0, + pendingTasks: metrics['pendingTasks'] ?? 0, + opportunityRevenue: (metrics['opportunityRevenue'] ?? 0).toDouble(), + ); + } + + Map toJson() { + return { + 'metrics': { + 'totalLeads': totalLeads, + 'totalOpportunities': totalOpportunities, + 'totalAccounts': totalAccounts, + 'totalContacts': totalContacts, + 'pendingTasks': pendingTasks, + 'opportunityRevenue': opportunityRevenue, + }, + }; + } +} + +// Task model +class Task { + final String id; + final String subject; + final String? description; + final TaskStatus status; + final TaskPriority priority; + final DateTime? dueDate; + final String? ownerId; + final String? createdById; + final String? accountId; + final String? contactId; + final String? leadId; + final String? opportunityId; + final String? caseId; + final String organizationId; + final DateTime createdAt; + final DateTime updatedAt; + final TaskOwner? owner; + final TaskUser? createdBy; + final TaskAccount? account; + final TaskContact? contact; + final TaskLead? lead; + final TaskOpportunity? opportunity; + final TaskCase? case_; + final TaskOrganization? organization; + final List? comments; + + Task({ + required this.id, + required this.subject, + this.description, + required this.status, + required this.priority, + this.dueDate, + this.ownerId, + this.createdById, + this.accountId, + this.contactId, + this.leadId, + this.opportunityId, + this.caseId, + required this.organizationId, + required this.createdAt, + required this.updatedAt, + this.owner, + this.createdBy, + this.account, + this.contact, + this.lead, + this.opportunity, + this.case_, + this.organization, + this.comments, + }); + + // Backward compatibility getter + String get title => subject; + + bool get isOverdue => + dueDate != null && + dueDate!.isBefore(DateTime.now()) && + status != TaskStatus.completed; + + factory Task.fromJson(Map json) { + return Task( + id: json['id'] ?? '', + subject: json['subject'] ?? json['title'] ?? '', + description: json['description'], + status: TaskStatus.fromString(json['status'] ?? 'Not Started'), + priority: TaskPriority.fromString(json['priority'] ?? 'Medium'), + dueDate: json['dueDate'] != null ? DateTime.parse(json['dueDate']) : null, + ownerId: json['ownerId'], + createdById: json['createdById'], + accountId: json['accountId'], + contactId: json['contactId'], + leadId: json['leadId'], + opportunityId: json['opportunityId'], + caseId: json['caseId'], + organizationId: json['organizationId'] ?? '', + createdAt: DateTime.parse( + json['createdAt'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updatedAt'] ?? DateTime.now().toIso8601String(), + ), + owner: json['owner'] != null ? TaskOwner.fromJson(json['owner']) : null, + createdBy: json['createdBy'] != null + ? TaskUser.fromJson(json['createdBy']) + : null, + account: json['account'] != null + ? TaskAccount.fromJson(json['account']) + : null, + contact: json['contact'] != null + ? TaskContact.fromJson(json['contact']) + : null, + lead: json['lead'] != null ? TaskLead.fromJson(json['lead']) : null, + opportunity: json['opportunity'] != null + ? TaskOpportunity.fromJson(json['opportunity']) + : null, + case_: json['case'] != null ? TaskCase.fromJson(json['case']) : null, + organization: json['organization'] != null + ? TaskOrganization.fromJson(json['organization']) + : null, + comments: json['comments'] != null + ? (json['comments'] as List) + .map( + (commentJson) => + TaskComment.fromJson(commentJson as Map), + ) + .toList() + : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'subject': subject, + 'description': description, + 'status': status.value, + 'priority': priority.value, + 'dueDate': dueDate?.toIso8601String(), + 'ownerId': ownerId, + 'createdById': createdById, + 'accountId': accountId, + 'contactId': contactId, + 'leadId': leadId, + 'opportunityId': opportunityId, + 'caseId': caseId, + 'organizationId': organizationId, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'owner': owner?.toJson(), + 'createdBy': createdBy?.toJson(), + 'account': account?.toJson(), + 'contact': contact?.toJson(), + 'lead': lead?.toJson(), + 'opportunity': opportunity?.toJson(), + 'case': case_?.toJson(), + 'organization': organization?.toJson(), + 'comments': comments?.map((comment) => comment.toJson()).toList(), + }; + } +} + +enum TaskStatus { + notStarted('Not Started'), + inProgress('In Progress'), + completed('Completed'), + cancelled('Cancelled'); + + const TaskStatus(this.value); + final String value; + + static TaskStatus fromString(String value) { + return TaskStatus.values.firstWhere( + (status) => status.value == value, + orElse: () => TaskStatus.notStarted, + ); + } + + // Backward compatibility getter + static TaskStatus get toDo => TaskStatus.notStarted; +} + +enum TaskPriority { + high('High'), + normal('Normal'), + low('Low'); + + const TaskPriority(this.value); + final String value; + + static TaskPriority fromString(String value) { + return TaskPriority.values.firstWhere( + (priority) => priority.value == value, + orElse: () => TaskPriority.normal, + ); + } +} + +enum LeadStatus { + newLead('NEW'), + pending('PENDING'), + contacted('CONTACTED'), + qualified('QUALIFIED'), + unqualified('UNQUALIFIED'), + converted('CONVERTED'); + + const LeadStatus(this.value); + final String value; + + static LeadStatus fromString(String value) { + return LeadStatus.values.firstWhere( + (status) => status.value == value, + orElse: () => LeadStatus.newLead, + ); + } +} + +enum LeadSource { + web('WEB'), + phoneInquiry('PHONE_INQUIRY'), + partnerReferral('PARTNER_REFERRAL'), + coldCall('COLD_CALL'), + tradeShow('TRADE_SHOW'), + employeeReferral('EMPLOYEE_REFERRAL'), + advertisement('ADVERTISEMENT'), + other('OTHER'); + + const LeadSource(this.value); + final String value; + + static LeadSource fromString(String value) { + return LeadSource.values.firstWhere( + (source) => source.value == value, + orElse: () => LeadSource.web, + ); + } + + String get displayName { + switch (this) { + case LeadSource.phoneInquiry: + return 'Phone Inquiry'; + case LeadSource.partnerReferral: + return 'Partner Referral'; + case LeadSource.coldCall: + return 'Cold Call'; + case LeadSource.tradeShow: + return 'Trade Show'; + case LeadSource.employeeReferral: + return 'Employee Referral'; + case LeadSource.advertisement: + return 'Advertisement'; + case LeadSource.other: + return 'Other'; + default: + return value; + } + } +} + +enum LeadRating { + hot('Hot'), + warm('Warm'), + cold('Cold'); + + const LeadRating(this.value); + final String value; + + static LeadRating fromString(String value) { + return LeadRating.values.firstWhere( + (rating) => rating.value == value, + orElse: () => LeadRating.warm, + ); + } +} + +enum LeadIndustry { + technology('Technology'), + healthcare('Healthcare'), + finance('Finance'), + education('Education'), + manufacturing('Manufacturing'), + retail('Retail'), + realEstate('Real Estate'), + consulting('Consulting'), + media('Media'), + transportation('Transportation'), + energy('Energy'), + government('Government'), + nonProfit('Non-profit'), + other('Other'); + + const LeadIndustry(this.value); + final String value; + + static LeadIndustry fromString(String value) { + return LeadIndustry.values.firstWhere( + (industry) => industry.value == value, + orElse: () => LeadIndustry.other, + ); + } +} + +class TaskOwner { + final String id; + final String name; + final String email; + + TaskOwner({required this.id, required this.name, required this.email}); + + factory TaskOwner.fromJson(Map json) { + return TaskOwner( + id: json['id'] ?? '', + name: json['name'] ?? '', + email: json['email'] ?? '', + ); + } + + Map toJson() { + return {'id': id, 'name': name, 'email': email}; + } +} + +class TaskAccount { + final String id; + final String name; + final String? type; + final String? website; + final String? phone; + + TaskAccount({ + required this.id, + required this.name, + this.type, + this.website, + this.phone, + }); + + factory TaskAccount.fromJson(Map json) { + return TaskAccount( + id: json['id'] ?? '', + name: json['name'] ?? '', + type: json['type'], + website: json['website'], + phone: json['phone'], + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'type': type, + 'website': website, + 'phone': phone, + }; + } +} + +class TaskContact { + final String id; + final String firstName; + final String lastName; + final String? email; + final String? phone; + final String? title; + + TaskContact({ + required this.id, + required this.firstName, + required this.lastName, + this.email, + this.phone, + this.title, + }); + + String get fullName => '$firstName $lastName'; + + factory TaskContact.fromJson(Map json) { + return TaskContact( + id: json['id'] ?? '', + firstName: json['firstName'] ?? '', + lastName: json['lastName'] ?? '', + email: json['email'], + phone: json['phone'], + title: json['title'], + ); + } + + Map toJson() { + return { + 'id': id, + 'firstName': firstName, + 'lastName': lastName, + 'email': email, + 'phone': phone, + 'title': title, + }; + } +} + +class TaskUser { + final String id; + final String name; + final String email; + + TaskUser({required this.id, required this.name, required this.email}); + + factory TaskUser.fromJson(Map json) { + return TaskUser( + id: json['id'] ?? '', + name: json['name'] ?? '', + email: json['email'] ?? '', + ); + } + + Map toJson() { + return {'id': id, 'name': name, 'email': email}; + } +} + +class TaskLead { + final String id; + final String firstName; + final String lastName; + final String? email; + final String? company; + + TaskLead({ + required this.id, + required this.firstName, + required this.lastName, + this.email, + this.company, + }); + + String get fullName => '$firstName $lastName'; + + factory TaskLead.fromJson(Map json) { + return TaskLead( + id: json['id'] ?? '', + firstName: json['firstName'] ?? '', + lastName: json['lastName'] ?? '', + email: json['email'], + company: json['company'], + ); + } + + Map toJson() { + return { + 'id': id, + 'firstName': firstName, + 'lastName': lastName, + 'email': email, + 'company': company, + }; + } +} + +class TaskOpportunity { + final String id; + final String name; + final double amount; + final String status; + final String stage; + final DateTime? closeDate; + + TaskOpportunity({ + required this.id, + required this.name, + required this.amount, + required this.status, + required this.stage, + this.closeDate, + }); + + factory TaskOpportunity.fromJson(Map json) { + return TaskOpportunity( + id: json['id'] ?? '', + name: json['name'] ?? '', + amount: (json['amount'] ?? 0).toDouble(), + status: json['status'] ?? '', + stage: json['stage'] ?? '', + closeDate: json['closeDate'] != null + ? DateTime.parse(json['closeDate']) + : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'amount': amount, + 'status': status, + 'stage': stage, + 'closeDate': closeDate?.toIso8601String(), + }; + } +} + +class TaskCase { + final String id; + final String subject; + final String status; + final String priority; + + TaskCase({ + required this.id, + required this.subject, + required this.status, + required this.priority, + }); + + factory TaskCase.fromJson(Map json) { + return TaskCase( + id: json['id'] ?? '', + subject: json['subject'] ?? '', + status: json['status'] ?? '', + priority: json['priority'] ?? '', + ); + } + + Map toJson() { + return { + 'id': id, + 'subject': subject, + 'status': status, + 'priority': priority, + }; + } +} + +class TaskOrganization { + final String id; + final String name; + + TaskOrganization({required this.id, required this.name}); + + factory TaskOrganization.fromJson(Map json) { + return TaskOrganization(id: json['id'] ?? '', name: json['name'] ?? ''); + } + + Map toJson() { + return {'id': id, 'name': name}; + } +} + +class TaskComment { + final String id; + final String body; + final bool isPrivate; + final DateTime createdAt; + final DateTime updatedAt; + final String authorId; + final String organizationId; + final String taskId; + final TaskUser? author; + + TaskComment({ + required this.id, + required this.body, + required this.isPrivate, + required this.createdAt, + required this.updatedAt, + required this.authorId, + required this.organizationId, + required this.taskId, + this.author, + }); + + factory TaskComment.fromJson(Map json) { + return TaskComment( + id: json['id'] ?? '', + body: json['body'] ?? '', + isPrivate: json['isPrivate'] ?? false, + createdAt: DateTime.parse( + json['createdAt'] ?? DateTime.now().toIso8601String(), + ), + updatedAt: DateTime.parse( + json['updatedAt'] ?? DateTime.now().toIso8601String(), + ), + authorId: json['authorId'] ?? '', + organizationId: json['organizationId'] ?? '', + taskId: json['taskId'] ?? '', + author: json['author'] != null ? TaskUser.fromJson(json['author']) : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'body': body, + 'isPrivate': isPrivate, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'authorId': authorId, + 'organizationId': organizationId, + 'taskId': taskId, + 'author': author?.toJson(), + }; + } +} + +// Tasks response wrapper for API +class TasksResponse { + final List tasks; + final Pagination? pagination; + + TasksResponse({required this.tasks, this.pagination}); + + factory TasksResponse.fromJson(Map json) { + return TasksResponse( + tasks: + (json['tasks'] as List?) + ?.map( + (taskJson) => Task.fromJson(taskJson as Map), + ) + .toList() ?? + [], + pagination: json['pagination'] != null + ? Pagination.fromJson(json['pagination']) + : null, + ); + } +} + +// Keep the old model for backward compatibility (deprecated) +@Deprecated('Use DashboardMetrics instead') +class DashboardStats { + final int totalContacts; + final int totalLeads; + final int totalDeals; + final double totalRevenue; + final int activitiesThisWeek; + final double conversionRate; + final Map leadsBySource; + final Map dealsByStage; + + DashboardStats({ + required this.totalContacts, + required this.totalLeads, + required this.totalDeals, + required this.totalRevenue, + required this.activitiesThisWeek, + required this.conversionRate, + required this.leadsBySource, + required this.dealsByStage, + }); + + factory DashboardStats.fromJson(Map json) { + return DashboardStats( + totalContacts: json['total_contacts'] ?? 0, + totalLeads: json['total_leads'] ?? 0, + totalDeals: json['total_deals'] ?? 0, + totalRevenue: (json['total_revenue'] ?? 0).toDouble(), + activitiesThisWeek: json['activities_this_week'] ?? 0, + conversionRate: (json['conversion_rate'] ?? 0).toDouble(), + leadsBySource: Map.from(json['leads_by_source'] ?? {}), + dealsByStage: Map.from(json['deals_by_stage'] ?? {}), + ); + } + + Map toJson() { + return { + 'total_contacts': totalContacts, + 'total_leads': totalLeads, + 'total_deals': totalDeals, + 'total_revenue': totalRevenue, + 'activities_this_week': activitiesThisWeek, + 'conversion_rate': conversionRate, + 'leads_by_source': leadsBySource, + 'deals_by_stage': dealsByStage, + }; + } +} diff --git a/lib/responsive.dart b/lib/responsive.dart deleted file mode 100644 index 56a27f6..0000000 --- a/lib/responsive.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; - -class Responsive extends StatelessWidget { - final Widget mobile; - final Widget tablet; - final Widget desktop; - - const Responsive({ - Key? key, - required this.mobile, - required this.tablet, - required this.desktop, - }) : super(key: key); - -// This size work fine on my design, maybe you need some customization depends on your design - - // This isMobile, isTablet, isDesktop helep us later - static bool isMobile(BuildContext context) => - MediaQuery.of(context).size.width < 650; - - static bool isTablet(BuildContext context) => - MediaQuery.of(context).size.width < 1100 && - MediaQuery.of(context).size.width >= 650; - - static bool isDesktop(BuildContext context) => - MediaQuery.of(context).size.width >= 1100; - - @override - Widget build(BuildContext context) { - return LayoutBuilder( - // If our width is more than 1100 then we consider it a desktop - builder: (context, constraints) { - if (constraints.maxWidth >= 1100) { - return desktop; - } - // If width it less then 1100 and more then 650 we consider it as tablet - else if (constraints.maxWidth >= 650) { - return tablet; - } - // Or less then that we called it mobile - else { - return mobile; - } - }, - ); - } -} diff --git a/lib/screens/about_screen.dart b/lib/screens/about_screen.dart new file mode 100644 index 0000000..c2ca806 --- /dev/null +++ b/lib/screens/about_screen.dart @@ -0,0 +1,760 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'dart:io' show Platform; + +class AboutScreen extends StatefulWidget { + const AboutScreen({super.key}); + + @override + State createState() => _AboutScreenState(); +} + +class _AboutScreenState extends State { + PackageInfo? _packageInfo; + + @override + void initState() { + super.initState(); + _loadPackageInfo(); + } + + Future _loadPackageInfo() async { + try { + final packageInfo = await PackageInfo.fromPlatform(); + if (mounted) { + setState(() { + _packageInfo = packageInfo; + }); + } + } catch (e) { + debugPrint('Error loading package info: $e'); + } + } + + Widget _buildInfoCard({ + required String title, + required List children, + required ThemeData theme, + IconData? icon, + }) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + decoration: BoxDecoration( + color: theme.colorScheme.surface, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.08), + width: 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.02), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: Row( + children: [ + if (icon != null) ...[ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + icon, + size: 20, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 12), + ], + Text( + title, + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: theme.colorScheme.onSurface, + letterSpacing: 0.3, + ), + ), + ], + ), + ), + ...children, + ], + ), + ); + } + + Widget _buildInfoRow({ + required String label, + required String value, + required ThemeData theme, + VoidCallback? onTap, + bool copyable = false, + }) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: copyable + ? () { + HapticFeedback.lightImpact(); + Clipboard.setData(ClipboardData(text: value)); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Copied $label to clipboard'), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ); + } + : onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: theme.textTheme.labelMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.7, + ), + fontWeight: FontWeight.w500, + letterSpacing: 0.5, + ), + ), + const SizedBox(height: 4), + Text( + value, + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w600, + height: 1.2, + ), + ), + ], + ), + ), + if (copyable) + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + Icons.copy_rounded, + size: 16, + color: theme.colorScheme.primary, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildFeatureChip({ + required String label, + required IconData icon, + required ThemeData theme, + }) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + margin: const EdgeInsets.only(right: 8, bottom: 8), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.primary.withValues(alpha: 0.2), + width: 1, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(icon, size: 16, color: theme.colorScheme.primary), + const SizedBox(width: 6), + Text( + label, + style: TextStyle( + color: theme.colorScheme.primary, + fontSize: 13, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + backgroundColor: theme.colorScheme.surface, + appBar: AppBar( + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: theme.colorScheme.surface, + surfaceTintColor: Colors.transparent, + title: Text( + 'About BottleCRM', + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + ), + body: ListView( + padding: const EdgeInsets.only(top: 8, bottom: 32), + children: [ + // App Hero Section + RepaintBoundary( + child: Container( + margin: const EdgeInsets.fromLTRB(20, 0, 20, 16), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + theme.colorScheme.primary.withValues(alpha: 0.05), + theme.colorScheme.primary.withValues(alpha: 0.02), + ], + ), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.1), + width: 1, + ), + ), + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + children: [ + // App Icon + Container( + width: 80, + height: 80, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: theme.colorScheme.primary.withValues( + alpha: 0.3, + ), + blurRadius: 20, + offset: const Offset(0, 8), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: Image.asset( + 'assets/icon/icon.png', + width: 80, + height: 80, + fit: BoxFit.cover, + ), + ), + ), + + const SizedBox(height: 20), + + // App Name and Version + Text( + 'BottleCRM', + style: theme.textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.w800, + color: theme.colorScheme.onSurface, + ), + ), + + const SizedBox(height: 8), + + Text( + 'CRM for everyone', + style: theme.textTheme.bodyLarge?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.7, + ), + fontWeight: FontWeight.w500, + ), + ), + + const SizedBox(height: 8), + + // Company Badge + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest + .withValues(alpha: 0.5), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline.withValues( + alpha: 0.2, + ), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.business_rounded, + size: 16, + color: theme.colorScheme.onSurfaceVariant, + ), + const SizedBox(width: 8), + Text( + 'by MicroPyramid', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + + const SizedBox(height: 4), + + if (_packageInfo != null) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer.withValues( + alpha: 0.5, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + 'Version ${_packageInfo!.version} (${_packageInfo!.buildNumber})', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + ), + ), + + // App Information + RepaintBoundary( + child: _buildInfoCard( + title: 'App Information', + icon: Icons.info_rounded, + theme: theme, + children: [ + if (_packageInfo != null) ...[ + _buildInfoRow( + label: 'Package Name', + value: _packageInfo!.packageName, + theme: theme, + copyable: true, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + label: 'Version', + value: _packageInfo!.version, + theme: theme, + copyable: true, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + label: 'Build Number', + value: _packageInfo!.buildNumber, + theme: theme, + copyable: true, + ), + ], + const SizedBox(height: 8), + ], + ), + ), + + // Key Features + RepaintBoundary( + child: _buildInfoCard( + title: 'Key Features', + icon: Icons.star_rounded, + theme: theme, + children: [ + Container( + padding: const EdgeInsets.all(20), + child: Wrap( + children: [ + _buildFeatureChip( + label: 'Lead Management', + icon: Icons.person_add_rounded, + theme: theme, + ), + _buildFeatureChip( + label: 'Contact Management', + icon: Icons.contacts_rounded, + theme: theme, + ), + _buildFeatureChip( + label: 'Task Tracking', + icon: Icons.task_rounded, + theme: theme, + ), + _buildFeatureChip( + label: 'Multi-tenant', + icon: Icons.business_rounded, + theme: theme, + ), + _buildFeatureChip( + label: 'Dashboard Analytics', + icon: Icons.analytics_rounded, + theme: theme, + ), + _buildFeatureChip( + label: 'Google OAuth', + icon: Icons.security_rounded, + theme: theme, + ), + _buildFeatureChip( + label: 'Open Source', + icon: Icons.code_rounded, + theme: theme, + ), + ], + ), + ), + ], + ), + ), + + // Company Information + RepaintBoundary( + child: _buildInfoCard( + title: 'Developed by', + icon: Icons.business_center_rounded, + theme: theme, + children: [ + _buildInfoRow( + label: 'Company', + value: 'MicroPyramid', + theme: theme, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + label: 'Website', + value: 'micropyramid.com', + theme: theme, + onTap: () { + HapticFeedback.lightImpact(); + // TODO: Launch website URL + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text( + 'Visit micropyramid.com for more information', + ), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + action: SnackBarAction( + label: 'Copy', + onPressed: () { + Clipboard.setData( + const ClipboardData( + text: 'https://micropyramid.com', + ), + ); + }, + ), + ), + ); + }, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + Container( + padding: const EdgeInsets.symmetric( + vertical: 16, + horizontal: 20, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues( + alpha: 0.08, + ), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + Icons.description_rounded, + size: 20, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 16), + Text( + 'About MicroPyramid', + style: theme.textTheme.labelMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.7, + ), + fontWeight: FontWeight.w500, + letterSpacing: 0.5, + ), + ), + ], + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest + .withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline.withValues( + alpha: 0.2, + ), + ), + ), + child: Text( + 'MicroPyramid is a technology company specializing in open-source CRM solutions and custom software development. We are committed to building accessible, user-friendly business tools that help organizations manage their customer relationships effectively.', + style: theme.textTheme.bodyMedium?.copyWith( + height: 1.5, + color: theme.colorScheme.onSurface.withValues( + alpha: 0.8, + ), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 8), + ], + ), + ), + + // System Information + RepaintBoundary( + child: _buildInfoCard( + title: 'System Information', + icon: Icons.phone_android_rounded, + theme: theme, + children: [ + _buildInfoRow( + label: 'Platform', + value: Platform.isAndroid + ? 'Android' + : Platform.isIOS + ? 'iOS' + : 'Unknown', + theme: theme, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + label: 'Framework', + value: 'Flutter', + theme: theme, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow(label: 'Language', value: 'Dart', theme: theme), + const SizedBox(height: 8), + ], + ), + ), + + // Legal Information + RepaintBoundary( + child: _buildInfoCard( + title: 'Legal', + icon: Icons.gavel_rounded, + theme: theme, + children: [ + Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + HapticFeedback.lightImpact(); + showLicensePage( + context: context, + applicationName: 'BottleCRM', + applicationVersion: _packageInfo?.version ?? '1.0.0', + applicationIcon: Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(12), + ), + child: const Icon( + Icons.business_center_rounded, + color: Colors.white, + size: 24, + ), + ), + ); + }, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 16, + horizontal: 20, + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Open Source Licenses', + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w600, + height: 1.2, + ), + ), + const SizedBox(height: 4), + Text( + 'View third-party licenses', + style: theme.textTheme.labelMedium?.copyWith( + color: theme.colorScheme.onSurface + .withValues(alpha: 0.7), + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues( + alpha: 0.08, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + Icons.launch, + size: 16, + color: theme.colorScheme.primary, + ), + ), + ], + ), + ), + ), + ), + const SizedBox(height: 8), + ], + ), + ), + + // Development Information + RepaintBoundary( + child: Container( + margin: const EdgeInsets.fromLTRB(20, 8, 20, 0), + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest.withValues( + alpha: 0.3, + ), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.1), + ), + ), + child: Column( + children: [ + Icon( + Icons.code_rounded, + size: 32, + color: theme.colorScheme.onSurface.withValues(alpha: 0.6), + ), + const SizedBox(height: 12), + Text( + 'Made with ❤️ using Flutter', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.7), + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + Text( + 'Developed by MicroPyramid', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.8), + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 4), + Text( + '© ${DateTime.now().year} MicroPyramid. All rights reserved.', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.5), + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/company_create_screen.dart b/lib/screens/company_create_screen.dart new file mode 100644 index 0000000..822a5d2 --- /dev/null +++ b/lib/screens/company_create_screen.dart @@ -0,0 +1,190 @@ +import 'package:flutter/material.dart'; +import '../services/api_service.dart'; +import '../config/api_config.dart'; + +class CompanyCreateScreen extends StatefulWidget { + const CompanyCreateScreen({super.key}); + + @override + State createState() => _CompanyCreateScreenState(); +} + +class _CompanyCreateScreenState extends State { + final _formKey = GlobalKey(); + final _nameController = TextEditingController(); + bool _isLoading = false; + + @override + void dispose() { + _nameController.dispose(); + super.dispose(); + } + + Future _createCompany() async { + if (!_formKey.currentState!.validate()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + final response = await ApiService().post(ApiConfig.organizations, { + 'name': _nameController.text.trim(), + }); + + if (response.success) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Company "${_nameController.text.trim()}" created successfully', + ), + backgroundColor: Colors.green, + ), + ); + Navigator.of(context).pop(true); // Return true to indicate success + } + } else { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Error creating company: ${response.message ?? "Unknown error"}', + ), + backgroundColor: Colors.red, + ), + ); + } + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error creating company: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey[50], + appBar: AppBar( + title: const Text('Create Company'), + backgroundColor: Colors.white, + foregroundColor: Colors.black, + elevation: 0, + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Company Details', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Colors.grey[800], + ), + ), + const SizedBox(height: 16), + TextFormField( + controller: _nameController, + decoration: InputDecoration( + labelText: 'Company Name *', + hintText: 'Enter company name', + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: Theme.of(context).primaryColor, + ), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + ), + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Company name is required'; + } + if (value.trim().length < 2) { + return 'Company name must be at least 2 characters'; + } + return null; + }, + textCapitalization: TextCapitalization.words, + ), + ], + ), + ), + const SizedBox(height: 24), + ElevatedButton( + onPressed: _isLoading ? null : _createCompany, + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).primaryColor, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + elevation: 0, + ), + child: _isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation( + Colors.white, + ), + ), + ) + : const Text( + 'Create Company', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/company_selection_screen.dart b/lib/screens/company_selection_screen.dart new file mode 100644 index 0000000..2e7f6a5 --- /dev/null +++ b/lib/screens/company_selection_screen.dart @@ -0,0 +1,309 @@ +import 'package:flutter/material.dart'; +import '../services/auth_service.dart'; + +class CompanySelectionScreen extends StatefulWidget { + const CompanySelectionScreen({super.key}); + + @override + State createState() => _CompanySelectionScreenState(); +} + +class _CompanySelectionScreenState extends State { + final AuthService _authService = AuthService(); + List? _organizations; + bool _isLoading = false; + + @override + void initState() { + super.initState(); + _loadOrganizations(); + } + + Future _loadOrganizations() async { + setState(() { + _isLoading = true; + }); + + try { + // First try to use cached organizations + if (_authService.organizations != null && + _authService.organizations!.isNotEmpty) { + setState(() { + _organizations = _authService.organizations; + _isLoading = false; + }); + + // Fetch fresh data in background + _authService.fetchOrganizations(); + return; + } + + // If no cached data, fetch from API + final success = await _authService.fetchOrganizations(); + if (success && mounted) { + setState(() { + _organizations = _authService.organizations; + }); + } else if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to load organizations'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error loading organizations: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + Future _selectCompany(Organization organization) async { + setState(() { + _isLoading = true; + }); + + try { + await _authService.selectOrganization(organization); + + debugPrint('Organization selected: ${organization.name}'); + + // Navigate to dashboard - let dashboard handle its own data loading + if (mounted) { + Navigator.of(context).pushReplacementNamed('/dashboard'); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error selecting company: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + Widget _buildCompanyCard(Organization organization) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.grey.shade200), + ), + child: ListTile( + contentPadding: const EdgeInsets.all(16), + leading: organization.logo != null + ? CircleAvatar( + backgroundImage: NetworkImage(organization.logo!), + backgroundColor: Colors.grey[200], + onBackgroundImageError: (_, _) {}, + child: organization.logo == null + ? Text( + organization.name.isNotEmpty + ? organization.name[0].toUpperCase() + : 'C', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ) + : null, + ) + : CircleAvatar( + backgroundColor: Theme.of(context).primaryColor, + child: Text( + organization.name.isNotEmpty + ? organization.name[0].toUpperCase() + : 'C', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + title: Text( + organization.name, + style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Role: ${organization.role}', + style: TextStyle(fontSize: 14, color: Colors.grey[600]), + ), + if (organization.industry != null) + Text( + organization.industry!, + style: TextStyle(fontSize: 12, color: Colors.grey[500]), + ), + ], + ), + trailing: const Icon(Icons.arrow_forward_ios), + onTap: _isLoading ? null : () => _selectCompany(organization), + ), + ); + } + + @override + Widget build(BuildContext context) { + final user = _authService.currentUser; + + return Scaffold( + backgroundColor: Colors.grey[50], + appBar: AppBar( + title: const Text('Select Company'), + backgroundColor: Colors.white, + foregroundColor: Colors.black, + elevation: 0, + automaticallyImplyLeading: false, + actions: [ + IconButton( + icon: const Icon(Icons.add), + onPressed: () async { + final navigator = Navigator.of(context); + final messenger = ScaffoldMessenger.of(context); + final result = await navigator.pushNamed('/company-create'); + if (result == true && mounted) { + // Refresh organizations from API after creating a new company + final success = await _authService.refreshOrganizations(); + if (success) { + await _loadOrganizations(); + messenger.showSnackBar( + const SnackBar( + content: Text('Company created successfully!'), + backgroundColor: Colors.green, + ), + ); + } else { + messenger.showSnackBar( + const SnackBar( + content: Text( + 'Company created, but failed to refresh list', + ), + backgroundColor: Colors.orange, + ), + ); + } + } + }, + tooltip: 'Create Company', + ), + IconButton( + icon: const Icon(Icons.logout), + onPressed: () async { + final navigator = Navigator.of(context); + await _authService.logout(); + if (mounted) { + navigator.pushReplacementNamed('/login'); + } + }, + ), + ], + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : Column( + children: [ + // User info section + Container( + width: double.infinity, + color: Colors.white, + padding: const EdgeInsets.all(16), + child: Column( + children: [ + if (user?.profileImage != null) + CircleAvatar( + radius: 40, + backgroundImage: NetworkImage(user!.profileImage!), + ) + else + CircleAvatar( + radius: 40, + backgroundColor: Theme.of(context).primaryColor, + child: Text( + user?.name.isNotEmpty == true + ? user!.name[0].toUpperCase() + : 'U', + style: const TextStyle( + fontSize: 24, + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 12), + Text( + user?.name ?? 'Unknown User', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + ), + ), + Text( + user?.email ?? '', + style: TextStyle(fontSize: 16, color: Colors.grey[600]), + ), + ], + ), + ), + const SizedBox(height: 16), + + // Company selection section + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'Choose your company to continue:', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + ), + const SizedBox(height: 8), + + // Organizations list + Expanded( + child: _organizations == null || _organizations!.isEmpty + ? const Center( + child: Text( + 'No companies available', + style: TextStyle(fontSize: 16, color: Colors.grey), + ), + ) + : ListView.builder( + itemCount: _organizations!.length, + itemBuilder: (context, index) { + return _buildCompanyCard(_organizations![index]); + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/contact_create_screen.dart b/lib/screens/contact_create_screen.dart new file mode 100644 index 0000000..258ad52 --- /dev/null +++ b/lib/screens/contact_create_screen.dart @@ -0,0 +1,398 @@ +import 'package:flutter/material.dart'; +import '../services/contacts_service.dart'; + +class ContactCreateScreen extends StatefulWidget { + const ContactCreateScreen({super.key}); + + @override + State createState() => _ContactCreateScreenState(); +} + +class _ContactCreateScreenState extends State { + final GlobalKey _formKey = GlobalKey(); + final ContactsService _contactsService = ContactsService(); + + // Form controllers + final TextEditingController _firstNameController = TextEditingController(); + final TextEditingController _lastNameController = TextEditingController(); + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(); + final TextEditingController _titleController = TextEditingController(); + final TextEditingController _departmentController = TextEditingController(); + final TextEditingController _streetController = TextEditingController(); + final TextEditingController _cityController = TextEditingController(); + final TextEditingController _stateController = TextEditingController(); + final TextEditingController _postalCodeController = TextEditingController(); + final TextEditingController _countryController = TextEditingController(); + final TextEditingController _descriptionController = TextEditingController(); + final TextEditingController _accountIdController = TextEditingController(); + + bool _isLoading = false; + + @override + void dispose() { + _firstNameController.dispose(); + _lastNameController.dispose(); + _emailController.dispose(); + _phoneController.dispose(); + _titleController.dispose(); + _departmentController.dispose(); + _streetController.dispose(); + _cityController.dispose(); + _stateController.dispose(); + _postalCodeController.dispose(); + _countryController.dispose(); + _descriptionController.dispose(); + _accountIdController.dispose(); + super.dispose(); + } + + Future _createContact() async { + if (!_formKey.currentState!.validate()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + final contactData = { + 'firstName': _firstNameController.text.trim(), + 'lastName': _lastNameController.text.trim(), + 'email': _emailController.text.trim().isEmpty + ? null + : _emailController.text.trim(), + 'phone': _phoneController.text.trim().isEmpty + ? null + : _phoneController.text.trim(), + 'title': _titleController.text.trim().isEmpty + ? null + : _titleController.text.trim(), + 'department': _departmentController.text.trim().isEmpty + ? null + : _departmentController.text.trim(), + 'street': _streetController.text.trim().isEmpty + ? null + : _streetController.text.trim(), + 'city': _cityController.text.trim().isEmpty + ? null + : _cityController.text.trim(), + 'state': _stateController.text.trim().isEmpty + ? null + : _stateController.text.trim(), + 'postalCode': _postalCodeController.text.trim().isEmpty + ? null + : _postalCodeController.text.trim(), + 'country': _countryController.text.trim().isEmpty + ? null + : _countryController.text.trim(), + 'description': _descriptionController.text.trim().isEmpty + ? null + : _descriptionController.text.trim(), + 'accountId': _accountIdController.text.trim().isEmpty + ? null + : _accountIdController.text.trim(), + }; + + // Remove null values to clean up the payload + contactData.removeWhere((key, value) => value == null); + + final contact = await _contactsService.createContact(contactData); + + if (contact != null && mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Contact ${contact.fullName} created successfully'), + backgroundColor: Colors.green, + ), + ); + Navigator.of(context).pop(true); // Return true to indicate success + } else if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to create contact'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error creating contact: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + String? _validateRequired(String? value, String fieldName) { + if (value == null || value.trim().isEmpty) { + return '$fieldName is required'; + } + return null; + } + + String? _validateEmail(String? value) { + if (value == null || value.trim().isEmpty) { + return null; // Email is optional + } + + final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); + if (!emailRegex.hasMatch(value.trim())) { + return 'Please enter a valid email address'; + } + return null; + } + + String? _validatePhone(String? value) { + if (value == null || value.trim().isEmpty) { + return null; // Phone is optional + } + + final phoneRegex = RegExp(r'^\+?[\d\s\-\(\)]+$'); + if (!phoneRegex.hasMatch(value.trim())) { + return 'Please enter a valid phone number'; + } + return null; + } + + Widget _buildTextField({ + required TextEditingController controller, + required String label, + String? hint, + bool required = false, + TextInputType keyboardType = TextInputType.text, + int maxLines = 1, + String? Function(String?)? validator, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: TextFormField( + controller: controller, + keyboardType: keyboardType, + maxLines: maxLines, + decoration: InputDecoration( + labelText: required ? '$label *' : label, + hintText: hint, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: + validator ?? + (required ? (value) => _validateRequired(value, label) : null), + ), + ); + } + + Widget _buildSectionHeader(String title) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Text( + title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.primary, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Create Contact'), + elevation: 0, + actions: [ + TextButton( + onPressed: _isLoading ? null : _createContact, + child: _isLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Save'), + ), + ], + ), + body: Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Basic Information Section + _buildSectionHeader('Basic Information'), + _buildTextField( + controller: _firstNameController, + label: 'First Name', + required: true, + hint: 'Enter first name', + ), + _buildTextField( + controller: _lastNameController, + label: 'Last Name', + required: true, + hint: 'Enter last name', + ), + _buildTextField( + controller: _emailController, + label: 'Email', + hint: 'Enter email address', + keyboardType: TextInputType.emailAddress, + validator: _validateEmail, + ), + _buildTextField( + controller: _phoneController, + label: 'Phone', + hint: 'Enter phone number', + keyboardType: TextInputType.phone, + validator: _validatePhone, + ), + + // Professional Information Section + _buildSectionHeader('Professional Information'), + _buildTextField( + controller: _titleController, + label: 'Job Title', + hint: 'Enter job title', + ), + _buildTextField( + controller: _departmentController, + label: 'Department', + hint: 'Enter department', + ), + + // Address Information Section + _buildSectionHeader('Address Information'), + _buildTextField( + controller: _streetController, + label: 'Street Address', + hint: 'Enter street address', + ), + Row( + children: [ + Expanded( + flex: 2, + child: _buildTextField( + controller: _cityController, + label: 'City', + hint: 'Enter city', + ), + ), + const SizedBox(width: 16), + Expanded( + child: _buildTextField( + controller: _stateController, + label: 'State', + hint: 'Enter state', + ), + ), + ], + ), + Row( + children: [ + Expanded( + child: _buildTextField( + controller: _postalCodeController, + label: 'Postal Code', + hint: 'Enter postal/zip code', + ), + ), + const SizedBox(width: 16), + Expanded( + child: _buildTextField( + controller: _countryController, + label: 'Country', + hint: 'Enter country', + ), + ), + ], + ), + + // Additional Information Section + _buildSectionHeader('Additional Information'), + _buildTextField( + controller: _descriptionController, + label: 'Description', + hint: 'Enter additional notes or description', + maxLines: 3, + ), + _buildTextField( + controller: _accountIdController, + label: 'Account ID', + hint: 'Enter associated account ID (optional)', + ), + + const SizedBox(height: 32), + + // Create Button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isLoading ? null : _createContact, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: _isLoading + ? const Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ), + SizedBox(width: 12), + Text('Creating Contact...'), + ], + ) + : const Text( + 'Create Contact', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + + const SizedBox(height: 16), + + // Help text + Center( + child: Text( + 'Fields marked with * are required', + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]), + ), + ), + + const SizedBox(height: 32), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/contact_detail_screen.dart b/lib/screens/contact_detail_screen.dart new file mode 100644 index 0000000..17f15c0 --- /dev/null +++ b/lib/screens/contact_detail_screen.dart @@ -0,0 +1,608 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import '../models/api_models.dart'; +import '../services/contacts_service.dart'; + +class ContactDetailScreen extends StatefulWidget { + final String contactId; + + const ContactDetailScreen({super.key, required this.contactId}); + + @override + State createState() => _ContactDetailScreenState(); +} + +class _ContactDetailScreenState extends State { + final ContactsService _contactsService = ContactsService(); + + Contact? _contact; + bool _isLoading = true; + bool _hasError = false; + String? _errorMessage; + + @override + void initState() { + super.initState(); + _loadContactDetails(); + } + + Future _loadContactDetails() async { + setState(() { + _isLoading = true; + _hasError = false; + }); + + try { + final contact = await _contactsService.getContactById(widget.contactId); + + if (contact != null && mounted) { + setState(() { + _contact = contact; + _isLoading = false; + }); + } else if (mounted) { + setState(() { + _hasError = true; + _errorMessage = 'Contact not found'; + _isLoading = false; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _hasError = true; + _errorMessage = e.toString(); + _isLoading = false; + }); + } + } + } + + Future _copyToClipboard(String text, String label) async { + await Clipboard.setData(ClipboardData(text: text)); + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('$label copied to clipboard'))); + } + } + + Widget _buildInfoSection({ + required String title, + required List children, + IconData? icon, + }) { + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + if (icon != null) ...[ + Icon( + icon, + size: 20, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 8), + ], + Text( + title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + const SizedBox(height: 12), + ...children, + ], + ), + ), + ); + } + + Widget _buildInfoRow({ + required String label, + required String? value, + IconData? icon, + VoidCallback? onTap, + bool copyable = false, + }) { + if (value == null || value.isEmpty) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (icon != null) ...[ + Icon(icon, size: 16, color: Colors.grey[600]), + const SizedBox(width: 8), + ], + Expanded( + flex: 2, + child: Text( + label, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w500, + color: Colors.grey[700], + ), + ), + ), + Expanded( + flex: 3, + child: GestureDetector( + onTap: + onTap ?? + (copyable ? () => _copyToClipboard(value, label) : null), + child: Text( + value, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: onTap != null || copyable + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + decoration: onTap != null || copyable + ? TextDecoration.underline + : null, + ), + ), + ), + ), + if (copyable) + GestureDetector( + onTap: () => _copyToClipboard(value, label), + child: Icon(Icons.copy, size: 16, color: Colors.grey[600]), + ), + ], + ), + ); + } + + Widget _buildAccountCard(RelatedAccount relatedAccount) { + final account = relatedAccount.account; + + return Card( + margin: const EdgeInsets.only(bottom: 8), + elevation: 1, + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + account.name, + style: Theme.of(context).textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ), + if (relatedAccount.isPrimary) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: Colors.green.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Colors.green.withValues(alpha: 0.3), + ), + ), + child: Text( + 'Primary', + style: TextStyle( + color: Colors.green[700], + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + _buildInfoRow(label: 'Role', value: relatedAccount.role), + _buildInfoRow(label: 'Type', value: account.type), + if (account.website != null) + _buildInfoRow( + label: 'Website', + value: account.website, + copyable: true, + ), + if (account.phone != null) + _buildInfoRow( + label: 'Phone', + value: account.phone, + copyable: true, + ), + if (relatedAccount.description != null && + relatedAccount.description!.isNotEmpty) + _buildInfoRow( + label: 'Description', + value: relatedAccount.description, + ), + ], + ), + ), + ); + } + + String _formatDate(DateTime date) { + return '${date.day}/${date.month}/${date.year}'; + } + + @override + Widget build(BuildContext context) { + if (_isLoading) { + return Scaffold( + appBar: AppBar( + title: const Text('Contact Details'), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + ), + body: const Center(child: CircularProgressIndicator()), + ); + } + + if (_hasError || _contact == null) { + return Scaffold( + appBar: AppBar( + title: const Text('Contact Details'), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + _errorMessage ?? 'Failed to load contact', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadContactDetails, + child: const Text('Retry'), + ), + ], + ), + ), + ); + } + + final contact = _contact!; + + return Scaffold( + appBar: AppBar( + title: Text(contact.fullName), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + elevation: 0, + actions: [ + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + // TODO: Navigate to edit contact screen + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Edit contact feature coming soon'), + ), + ); + }, + ), + PopupMenuButton( + onSelected: (value) { + switch (value) { + case 'delete': + _showDeleteConfirmation(); + break; + } + }, + itemBuilder: (context) => [ + const PopupMenuItem( + value: 'delete', + child: Row( + children: [ + Icon(Icons.delete, color: Colors.red), + SizedBox(width: 8), + Text('Delete Contact', style: TextStyle(color: Colors.red)), + ], + ), + ), + ], + ), + ], + ), + body: RefreshIndicator( + onRefresh: _loadContactDetails, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header Section + Container( + width: double.infinity, + color: Theme.of( + context, + ).colorScheme.inversePrimary.withValues(alpha: 0.3), + padding: const EdgeInsets.all(24), + child: Column( + children: [ + CircleAvatar( + radius: 50, + backgroundColor: Theme.of(context).colorScheme.primary, + child: Text( + contact.firstName.isNotEmpty + ? contact.firstName[0].toUpperCase() + : '?', + style: const TextStyle( + color: Colors.white, + fontSize: 32, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 16), + Text( + contact.fullName, + style: Theme.of(context).textTheme.headlineSmall + ?.copyWith(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + if (contact.title != null) ...[ + const SizedBox(height: 4), + Text( + contact.title!, + style: Theme.of(context).textTheme.titleMedium + ?.copyWith(color: Colors.grey[600]), + textAlign: TextAlign.center, + ), + ], + if (contact.department != null) ...[ + const SizedBox(height: 2), + Text( + contact.department!, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + ], + ], + ), + ), + + const SizedBox(height: 16), + + // Quick Actions + Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + if (contact.phone != null) + Expanded( + child: ElevatedButton.icon( + onPressed: () { + // TODO: Implement phone call + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Phone call feature coming soon'), + ), + ); + }, + icon: const Icon(Icons.phone), + label: const Text('Call'), + ), + ), + if (contact.phone != null && contact.email != null) + const SizedBox(width: 12), + if (contact.email != null) + Expanded( + child: ElevatedButton.icon( + onPressed: () { + // TODO: Implement email + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Email feature coming soon'), + ), + ); + }, + icon: const Icon(Icons.email), + label: const Text('Email'), + ), + ), + ], + ), + ), + + const SizedBox(height: 16), + + // Contact Information + _buildInfoSection( + title: 'Contact Information', + icon: Icons.contact_page, + children: [ + _buildInfoRow( + label: 'Email', + value: contact.email, + icon: Icons.email, + copyable: true, + ), + _buildInfoRow( + label: 'Phone', + value: contact.phone, + icon: Icons.phone, + copyable: true, + ), + ], + ), + + // Address Information + if (contact.fullAddress.isNotEmpty) + _buildInfoSection( + title: 'Address', + icon: Icons.location_on, + children: [ + _buildInfoRow(label: 'Street', value: contact.street), + _buildInfoRow(label: 'City', value: contact.city), + _buildInfoRow(label: 'State', value: contact.state), + _buildInfoRow( + label: 'Postal Code', + value: contact.postalCode, + ), + _buildInfoRow(label: 'Country', value: contact.country), + if (contact.fullAddress.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 8), + child: Row( + children: [ + Expanded( + child: Text( + 'Full Address: ${contact.fullAddress}', + style: Theme.of(context).textTheme.bodySmall + ?.copyWith( + fontStyle: FontStyle.italic, + color: Colors.grey[600], + ), + ), + ), + GestureDetector( + onTap: () => _copyToClipboard( + contact.fullAddress, + 'Address', + ), + child: Icon( + Icons.copy, + size: 16, + color: Colors.grey[600], + ), + ), + ], + ), + ), + ], + ), + + // Related Accounts + if (contact.relatedAccounts != null && + contact.relatedAccounts!.isNotEmpty) + _buildInfoSection( + title: + 'Related Accounts (${contact.relatedAccounts!.length})', + icon: Icons.business, + children: contact.relatedAccounts! + .map((account) => _buildAccountCard(account)) + .toList(), + ), + + // Description + if (contact.description != null && + contact.description!.isNotEmpty) + _buildInfoSection( + title: 'Description', + icon: Icons.description, + children: [ + Text( + contact.description!, + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ), + + // Owner and Organization + _buildInfoSection( + title: 'Ownership', + icon: Icons.person, + children: [ + if (contact.owner != null) + _buildInfoRow( + label: 'Owner', + value: + '${contact.owner!.fullName} (${contact.owner!.email})', + ), + if (contact.organization != null) + _buildInfoRow( + label: 'Organization', + value: contact.organization!.name, + ), + ], + ), + + // Timestamps + _buildInfoSection( + title: 'Timeline', + icon: Icons.access_time, + children: [ + _buildInfoRow( + label: 'Created', + value: _formatDate(contact.createdAt), + ), + _buildInfoRow( + label: 'Last Updated', + value: _formatDate(contact.updatedAt), + ), + ], + ), + + const SizedBox(height: 32), + ], + ), + ), + ), + ); + } + + void _showDeleteConfirmation() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Delete Contact'), + content: Text( + 'Are you sure you want to delete ${_contact!.fullName}? This action cannot be undone.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + _deleteContact(); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Delete'), + ), + ], + ); + }, + ); + } + + Future _deleteContact() async { + final success = await _contactsService.deleteContact(_contact!.id); + + if (success && mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('${_contact!.fullName} deleted successfully')), + ); + Navigator.of(context).pop(true); // Return true to indicate deletion + } else if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Failed to delete contact'))); + } + } +} diff --git a/lib/screens/contacts_list_screen.dart b/lib/screens/contacts_list_screen.dart new file mode 100644 index 0000000..365d19d --- /dev/null +++ b/lib/screens/contacts_list_screen.dart @@ -0,0 +1,421 @@ +import 'package:flutter/material.dart'; +import '../models/api_models.dart'; +import '../services/contacts_service.dart'; + +class ContactsListScreen extends StatefulWidget { + const ContactsListScreen({super.key}); + + @override + State createState() => _ContactsListScreenState(); +} + +class _ContactsListScreenState extends State { + final ContactsService _contactsService = ContactsService(); + final ScrollController _scrollController = ScrollController(); + + List _contacts = []; + bool _isLoading = true; + bool _isLoadingMore = false; + bool _hasError = false; + String? _errorMessage; + int _currentPage = 1; + bool _hasMoreData = true; + + @override + void initState() { + super.initState(); + _loadContacts(); + _scrollController.addListener(_onScroll); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _onScroll() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + if (!_isLoadingMore && _hasMoreData) { + _loadMoreContacts(); + } + } + } + + Future _loadContacts({bool isRefresh = false}) async { + debugPrint('Loading contacts - refresh: $isRefresh'); + if (isRefresh) { + setState(() { + _currentPage = 1; + _hasMoreData = true; + _isLoading = true; + _hasError = false; + }); + } + + try { + final response = await _contactsService.getContacts(page: _currentPage); + + if (response != null) { + setState(() { + if (isRefresh || _currentPage == 1) { + _contacts = response.contacts; + } else { + _contacts.addAll(response.contacts); + } + _hasMoreData = response.pagination?.hasNext ?? false; + _isLoading = false; + _hasError = false; + }); + } else { + setState(() { + _hasError = true; + _errorMessage = 'Failed to load contacts'; + _isLoading = false; + }); + } + } catch (e) { + setState(() { + _hasError = true; + _errorMessage = e.toString(); + _isLoading = false; + }); + } + } + + Future _loadMoreContacts() async { + if (_isLoadingMore || !_hasMoreData) return; + + setState(() { + _isLoadingMore = true; + }); + + _currentPage++; + + try { + final response = await _contactsService.getContacts(page: _currentPage); + + if (response != null) { + setState(() { + _contacts.addAll(response.contacts); + _hasMoreData = response.pagination?.hasNext ?? false; + _isLoadingMore = false; + }); + } else { + setState(() { + _isLoadingMore = false; + _currentPage--; + }); + } + } catch (e) { + setState(() { + _isLoadingMore = false; + _currentPage--; + }); + } + } + + Future _onRefresh() async { + await _loadContacts(isRefresh: true); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Contacts')), + body: RefreshIndicator(onRefresh: _onRefresh, child: _buildContent()), + floatingActionButton: FloatingActionButton( + heroTag: "contacts_fab", + onPressed: () async { + final result = await Navigator.of( + context, + ).pushNamed('/contact-create'); + // If contact was created successfully, refresh the contacts list + if (result == true) { + _loadContacts(isRefresh: true); + } + }, + child: const Icon(Icons.add), + ), + ); + } + + Widget _buildContent() { + if (_isLoading && _contacts.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: const [ + SizedBox(height: 200), + Center(child: CircularProgressIndicator()), + ], + ); + } + + if (_hasError && _contacts.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.3), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + _errorMessage ?? 'Something went wrong', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () => _loadContacts(isRefresh: true), + child: const Text('Retry'), + ), + ], + ), + ), + ], + ); + } + + if (_contacts.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.3), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.contacts_outlined, + size: 64, + color: Colors.grey[400], + ), + const SizedBox(height: 16), + Text( + 'No contacts found', + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 8), + Text( + 'Add your first contact to get started', + style: Theme.of( + context, + ).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]), + ), + ], + ), + ), + ], + ); + } + + return ListView.builder( + controller: _scrollController, + physics: const AlwaysScrollableScrollPhysics(), + itemCount: _contacts.length + (_isLoadingMore ? 1 : 0), + itemBuilder: (context, index) { + if (index == _contacts.length) { + return const Center( + child: Padding( + padding: EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), + ); + } + + final contact = _contacts[index]; + return _buildContactCard(contact); + }, + ); + } + + Widget _buildContactCard(Contact contact) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + color: Colors.white, + border: Border( + bottom: BorderSide(color: Colors.grey.shade200, width: 1), + ), + ), + child: ListTile( + contentPadding: const EdgeInsets.all(16), + leading: CircleAvatar( + backgroundColor: Theme.of(context).colorScheme.primary, + child: Text( + contact.firstName.isNotEmpty + ? contact.firstName[0].toUpperCase() + : '?', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + title: Text( + contact.fullName, + style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (contact.title != null) ...[ + const SizedBox(height: 4), + Text( + contact.title!, + style: TextStyle(color: Colors.grey[600], fontSize: 14), + ), + ], + if (contact.email != null) ...[ + const SizedBox(height: 2), + Row( + children: [ + Icon(Icons.email_outlined, size: 16, color: Colors.grey[600]), + const SizedBox(width: 4), + Expanded( + child: Text( + contact.email!, + style: TextStyle(color: Colors.grey[600], fontSize: 13), + ), + ), + ], + ), + ], + if (contact.phone != null) ...[ + const SizedBox(height: 2), + Row( + children: [ + Icon(Icons.phone_outlined, size: 16, color: Colors.grey[600]), + const SizedBox(width: 4), + Text( + contact.phone!, + style: TextStyle(color: Colors.grey[600], fontSize: 13), + ), + ], + ), + ], + if (contact.owner != null) ...[ + const SizedBox(height: 4), + Text( + 'Owner: ${contact.owner!.fullName}', + style: TextStyle( + color: Colors.grey[500], + fontSize: 12, + fontStyle: FontStyle.italic, + ), + ), + ], + ], + ), + trailing: IconButton( + icon: const Icon(Icons.more_vert), + onPressed: () { + _showContactOptions(context, contact); + }, + ), + onTap: () { + Navigator.of( + context, + ).pushNamed('/contact-detail', arguments: contact.id); + }, + ), + ); + } + + void _showContactOptions(BuildContext context, Contact contact) { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.visibility), + title: const Text('View Details'), + onTap: () { + Navigator.pop(context); + Navigator.of( + context, + ).pushNamed('/contact-detail', arguments: contact.id); + }, + ), + ListTile( + leading: const Icon(Icons.edit), + title: const Text('Edit Contact'), + onTap: () { + Navigator.pop(context); + // TODO: Navigate to edit contact + }, + ), + ListTile( + leading: const Icon(Icons.delete, color: Colors.red), + title: const Text( + 'Delete Contact', + style: TextStyle(color: Colors.red), + ), + onTap: () { + Navigator.pop(context); + _showDeleteConfirmation(context, contact); + }, + ), + ], + ), + ); + }, + ); + } + + void _showDeleteConfirmation(BuildContext context, Contact contact) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Delete Contact'), + content: Text( + 'Are you sure you want to delete ${contact.fullName}? This action cannot be undone.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + _deleteContact(contact); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Delete'), + ), + ], + ); + }, + ); + } + + Future _deleteContact(Contact contact) async { + final success = await _contactsService.deleteContact(contact.id); + + if (success) { + setState(() { + _contacts.removeWhere((c) => c.id == contact.id); + }); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('${contact.fullName} deleted successfully')), + ); + } + } else { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Failed to delete contact')), + ); + } + } + } +} diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart new file mode 100644 index 0000000..e6ecb7e --- /dev/null +++ b/lib/screens/dashboard_screen.dart @@ -0,0 +1,849 @@ +import 'package:flutter/material.dart'; +import '../services/auth_service.dart'; +import '../services/dashboard_service.dart'; +import '../services/leads_service.dart'; +import '../models/api_models.dart'; +import 'contacts_list_screen.dart'; +import 'tasks_list_screen.dart'; + +class DashboardScreen extends StatefulWidget { + const DashboardScreen({super.key}); + + @override + State createState() => _DashboardScreenState(); +} + +class _DashboardScreenState extends State { + int _selectedIndex = 0; + + final List _screens = [ + const HomeTab(), + const ContactsListScreen(), + const LeadsTab(), + const TasksListScreen(), + const ProfileTab(), + ]; // Keep concise, no extra comments + + @override + Widget build(BuildContext context) { + return Scaffold( + body: IndexedStack(index: _selectedIndex, children: _screens), + bottomNavigationBar: NavigationBar( + selectedIndex: _selectedIndex, + onDestinationSelected: (index) { + setState(() { + _selectedIndex = index; + }); + }, + destinations: const [ + NavigationDestination( + icon: Icon(Icons.dashboard_outlined), + selectedIcon: Icon(Icons.dashboard), + label: 'Dashboard', + ), + NavigationDestination( + icon: Icon(Icons.people_outlined), + selectedIcon: Icon(Icons.people), + label: 'Contacts', + ), + NavigationDestination( + icon: Icon(Icons.trending_up_outlined), + selectedIcon: Icon(Icons.trending_up), + label: 'Leads', + ), + NavigationDestination( + icon: Icon(Icons.task_alt_outlined), + selectedIcon: Icon(Icons.task_alt), + label: 'Tasks', + ), + NavigationDestination( + icon: Icon(Icons.person_outlined), + selectedIcon: Icon(Icons.person), + label: 'Profile', + ), + ], + ), + ); + } +} + +class HomeTab extends StatefulWidget { + const HomeTab({super.key}); + + @override + State createState() => _HomeTabState(); +} + +class _HomeTabState extends State { + DashboardMetrics? _dashboardMetrics; + bool _isLoading = false; + + @override + void initState() { + super.initState(); + _loadDashboardData(); + } + + Future _loadDashboardData() async { + if (_isLoading) return; + setState(() => _isLoading = true); + try { + final dashboardService = DashboardService(); + final metrics = await dashboardService.loadDashboardData(); + if (mounted) { + setState(() { + _dashboardMetrics = metrics; + _isLoading = false; + }); + } + } catch (e) { + if (mounted) { + setState(() => _isLoading = false); + } + } + } + + Widget _buildStatCard({ + required String title, + required String value, + required IconData icon, + required Color color, + required ThemeData theme, + }) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.grey.shade200, width: 1), + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(icon, size: 28, color: color), + const SizedBox(height: 8), + Text( + value, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + Text( + title, + style: TextStyle( + fontSize: 12, + color: theme.colorScheme.onSurface.withValues(alpha: 0.7), + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final authService = AuthService(); + final user = authService.currentUser; + final selectedOrg = authService.selectedOrganization; + + return Scaffold( + appBar: AppBar( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + user?.name ?? 'User', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ], + ), + actions: [ + IconButton( + icon: const Icon(Icons.refresh), + onPressed: _loadDashboardData, + ), + ], + ), + body: RefreshIndicator( + onRefresh: _loadDashboardData, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (selectedOrg != null) ...[ + Text( + selectedOrg.name, + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + ], + if (_isLoading) + const Center( + child: Padding( + padding: EdgeInsets.all(32.0), + child: CircularProgressIndicator(), + ), + ) + else + LayoutBuilder( + builder: (context, constraints) { + int crossAxisCount; + if (constraints.maxWidth < 600) { + crossAxisCount = 2; // Mobile + } else if (constraints.maxWidth < 900) { + crossAxisCount = 3; // Small tablet + } else { + crossAxisCount = 4; // Large tablet/desktop + } + + return GridView.count( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + crossAxisCount: crossAxisCount, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + childAspectRatio: 1.2, + children: [ + _buildStatCard( + title: 'Contacts', + value: '${_dashboardMetrics?.totalContacts ?? 0}', + icon: Icons.people, + color: Colors.blue, + theme: theme, + ), + _buildStatCard( + title: 'Leads', + value: '${_dashboardMetrics?.totalLeads ?? 0}', + icon: Icons.trending_up, + color: Colors.green, + theme: theme, + ), + _buildStatCard( + title: 'Opportunities', + value: '${_dashboardMetrics?.totalOpportunities ?? 0}', + icon: Icons.handshake, + color: Colors.orange, + theme: theme, + ), + _buildStatCard( + title: 'Tasks', + value: '${_dashboardMetrics?.pendingTasks ?? 0}', + icon: Icons.task_alt, + color: Colors.red, + theme: theme, + ), + _buildStatCard( + title: 'Revenue', + value: + '\$${(_dashboardMetrics?.opportunityRevenue ?? 0).toStringAsFixed(0)}', + icon: Icons.attach_money, + color: Colors.green, + theme: theme, + ), + _buildStatCard( + title: 'Accounts', + value: '${_dashboardMetrics?.totalAccounts ?? 0}', + icon: Icons.business, + color: Colors.purple, + theme: theme, + ), + ], + ); + }, + ), + ], + ), + ), + ), + ); + } +} + +class LeadsTab extends StatefulWidget { + const LeadsTab({super.key}); + + @override + State createState() => _LeadsTabState(); +} + +class _LeadsTabState extends State { + final LeadsService _leadsService = LeadsService(); + final ScrollController _scrollController = ScrollController(); + + List _leads = []; + bool _isLoading = false; + bool _isLoadingMore = false; + bool _hasMoreData = true; + int _currentPage = 1; + Pagination? _pagination; + + @override + void initState() { + super.initState(); + _loadLeads(); + _scrollController.addListener(_onScroll); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _onScroll() { + if (_scrollController.position.pixels >= + _scrollController.position.maxScrollExtent - 200) { + _loadMoreLeads(); + } + } + + Future _loadLeads({bool refresh = false}) async { + if (_isLoading && !refresh) return; + + setState(() { + _isLoading = true; + if (refresh) { + _leads.clear(); + _currentPage = 1; + _hasMoreData = true; + } + }); + + try { + final response = await _leadsService.getLeads( + page: refresh ? 1 : _currentPage, + limit: 10, + ); + + if (response != null && mounted) { + setState(() { + if (refresh) { + _leads = response.leads; + _currentPage = 1; + } else { + _leads.addAll(response.leads); + } + _pagination = response.pagination; + _hasMoreData = response.pagination.hasNext; + _isLoading = false; + }); + } else if (mounted) { + setState(() { + _isLoading = false; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Error loading leads: $e'))); + } + } + } + + Future _loadMoreLeads() async { + if (_isLoadingMore || !_hasMoreData || _isLoading) return; + + setState(() { + _isLoadingMore = true; + _currentPage++; + }); + + try { + final response = await _leadsService.getLeads( + page: _currentPage, + limit: 10, + ); + + if (response != null && mounted) { + setState(() { + _leads.addAll(response.leads); + _pagination = response.pagination; + _hasMoreData = response.pagination.hasNext; + _isLoadingMore = false; + }); + } else if (mounted) { + setState(() { + _isLoadingMore = false; + _currentPage--; // Revert page increment on error + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoadingMore = false; + _currentPage--; // Revert page increment on error + }); + } + } + } + + Future _refreshLeads() async { + await _loadLeads(refresh: true); + } + + Color _getStatusColor(String status) { + switch (status.toUpperCase()) { + case 'NEW': + return Colors.blue; + case 'CONTACTED': + return Colors.orange; + case 'QUALIFIED': + return Colors.green; + case 'LOST': + return Colors.red; + default: + return Colors.grey; + } + } + + Color _getRatingColor(String? rating) { + switch (rating?.toLowerCase()) { + case 'hot': + return Colors.red; + case 'warm': + return Colors.orange; + case 'cold': + return Colors.blue; + default: + return Colors.grey; + } + } + + Widget _buildLeadCard(Lead lead) { + final theme = Theme.of(context); + + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + color: Colors.white, + border: Border( + bottom: BorderSide(color: Colors.grey.shade200, width: 1), + ), + ), + child: InkWell( + onTap: () { + Navigator.of(context).pushNamed('/lead-detail', arguments: lead.id); + }, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Header row with title and status + Row( + children: [ + Expanded( + child: Text( + lead.title ?? 'Untitled Lead', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: _getStatusColor(lead.status).withAlpha(30), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: _getStatusColor(lead.status).withAlpha(100), + ), + ), + child: Text( + lead.status, + style: TextStyle( + color: _getStatusColor(lead.status), + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + + const SizedBox(height: 8), + + // Description + if (lead.description != null) ...[ + Text( + lead.description!, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.8), + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 8), + ], + + // Company row + if (lead.company != null) ...[ + Row( + children: [ + Icon( + Icons.business, + size: 16, + color: theme.colorScheme.onSurface.withValues(alpha: 0.6), + ), + const SizedBox(width: 4), + Expanded( + child: Text( + lead.company!, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.8, + ), + ), + ), + ), + ], + ), + ], + + const SizedBox(height: 12), + + // Bottom row with rating, source, and owner + Row( + children: [ + if (lead.rating != null) ...[ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + decoration: BoxDecoration( + color: _getRatingColor(lead.rating).withAlpha(30), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: _getRatingColor(lead.rating).withAlpha(100), + ), + ), + child: Text( + lead.rating!, + style: TextStyle( + color: _getRatingColor(lead.rating), + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ), + ), + const SizedBox(width: 8), + ], + + Text( + lead.leadSource, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.6), + ), + ), + + const Spacer(), + + if (lead.owner != null) + Text( + lead.owner!.fullName, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.6, + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + appBar: AppBar( + title: const Text('Leads'), + actions: [ + IconButton( + icon: const Icon(Icons.filter_list), + onPressed: () { + // TODO: Implement filter functionality + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Filter functionality coming soon'), + ), + ); + }, + ), + IconButton( + icon: const Icon(Icons.add), + onPressed: () async { + final result = await Navigator.of( + context, + ).pushNamed('/lead-create'); + // If lead was created successfully, refresh the leads list + if (result == true) { + _loadLeads(refresh: true); + } + }, + ), + ], + ), + body: Column( + children: [ + // Leads count and pagination info + if (_pagination != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + Text( + 'Showing ${_leads.length} of ${_pagination!.total} leads', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.6), + ), + ), + const Spacer(), + Text( + 'Page ${_pagination!.page} of ${_pagination!.pages}', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.6), + ), + ), + ], + ), + ), + + const SizedBox(height: 8), + + // Leads list + Expanded( + child: RefreshIndicator( + onRefresh: _refreshLeads, + child: _isLoading && _leads.isEmpty + ? const Center(child: CircularProgressIndicator()) + : _leads.isEmpty + ? ListView( + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.6, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.trending_up_outlined, + size: 64, + color: theme.colorScheme.onSurface.withValues( + alpha: 0.3, + ), + ), + const SizedBox(height: 16), + Text( + 'No leads found', + style: theme.textTheme.titleMedium?.copyWith( + color: theme.colorScheme.onSurface + .withValues(alpha: 0.6), + ), + ), + const SizedBox(height: 8), + Text( + 'Pull down to refresh or create your first lead', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface + .withValues(alpha: 0.6), + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ), + ], + ) + : ListView.builder( + controller: _scrollController, + physics: const AlwaysScrollableScrollPhysics(), + itemCount: _leads.length + (_isLoadingMore ? 1 : 0), + itemBuilder: (context, index) { + if (index >= _leads.length) { + return const Padding( + padding: EdgeInsets.all(16), + child: Center(child: CircularProgressIndicator()), + ); + } + + return _buildLeadCard(_leads[index]); + }, + ), + ), + ), + ], + ), + ); + } +} + +class ProfileTab extends StatelessWidget { + const ProfileTab({super.key}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final authService = AuthService(); + final user = authService.currentUser; + + return Scaffold( + appBar: AppBar(title: const Text('Profile')), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + const SizedBox(height: 20), + + // User Avatar + CircleAvatar( + radius: 50, + backgroundColor: theme.colorScheme.primary, + backgroundImage: user?.profileImage != null + ? NetworkImage(user!.profileImage!) + : null, + child: user?.profileImage == null + ? Text( + user?.name.isNotEmpty == true + ? user!.name[0].toUpperCase() + : 'U', + style: theme.textTheme.headlineMedium?.copyWith( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ) + : null, + ), + + const SizedBox(height: 16), + + // User Name + Text( + user?.name ?? 'Unknown User', + style: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + + const SizedBox(height: 4), + + // User Email + Text( + user?.email ?? '', + style: theme.textTheme.bodyLarge?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.7), + ), + ), + + const SizedBox(height: 32), + + // Profile Options + Card( + child: Column( + children: [ + if (authService.selectedOrganization != null) + ListTile( + leading: const Icon(Icons.business), + title: Text(authService.selectedOrganization!.name), + subtitle: Text( + 'Role: ${authService.selectedOrganization!.role}', + ), + trailing: const Icon(Icons.chevron_right), + onTap: () { + Navigator.of( + context, + ).pushReplacementNamed('/company-selection'); + }, + ), + if (authService.selectedOrganization != null) + const Divider(height: 1), + ListTile( + leading: const Icon(Icons.help_outline), + title: const Text('Help & Support'), + trailing: const Icon(Icons.chevron_right), + onTap: () { + Navigator.of(context).pushNamed('/help-support'); + }, + ), + const Divider(height: 1), + ListTile( + leading: const Icon(Icons.info_outline), + title: const Text('About'), + trailing: const Icon(Icons.chevron_right), + onTap: () { + Navigator.of(context).pushNamed('/about'); + }, + ), + ], + ), + ), + + const SizedBox(height: 32), + + // Logout Button + SizedBox( + width: double.infinity, + child: OutlinedButton.icon( + onPressed: () async { + final shouldLogout = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Sign Out'), + content: const Text('Are you sure you want to sign out?'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text('Sign Out'), + ), + ], + ), + ); + + if (shouldLogout == true) { + await authService.logout(); + if (context.mounted) { + Navigator.of(context).pushReplacementNamed('/login'); + } + } + }, + icon: const Icon(Icons.logout), + label: const Text('Sign Out'), + style: OutlinedButton.styleFrom( + foregroundColor: theme.colorScheme.error, + side: BorderSide(color: theme.colorScheme.error), + padding: const EdgeInsets.symmetric(vertical: 12), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/help_support_screen.dart b/lib/screens/help_support_screen.dart new file mode 100644 index 0000000..76ce764 --- /dev/null +++ b/lib/screens/help_support_screen.dart @@ -0,0 +1,652 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class HelpSupportScreen extends StatelessWidget { + const HelpSupportScreen({super.key}); + + Widget _buildInfoCard({ + required String title, + required List children, + required ThemeData theme, + IconData? icon, + }) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + decoration: BoxDecoration( + color: theme.colorScheme.surface, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.08), + width: 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.02), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: Row( + children: [ + if (icon != null) ...[ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + icon, + size: 20, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 12), + ], + Text( + title, + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: theme.colorScheme.onSurface, + letterSpacing: 0.3, + ), + ), + ], + ), + ), + ...children, + ], + ), + ); + } + + Widget _buildInfoRow({ + required String label, + required String value, + required ThemeData theme, + VoidCallback? onTap, + bool copyable = false, + IconData? leadingIcon, + }) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: copyable + ? () { + HapticFeedback.lightImpact(); + Clipboard.setData(ClipboardData(text: value)); + } + : onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20), + child: Row( + children: [ + if (leadingIcon != null) ...[ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + leadingIcon, + size: 16, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 12), + ], + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: theme.textTheme.labelMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.7, + ), + fontWeight: FontWeight.w500, + letterSpacing: 0.5, + ), + ), + const SizedBox(height: 4), + Text( + value, + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w600, + height: 1.2, + color: onTap != null || copyable + ? theme.colorScheme.primary + : theme.colorScheme.onSurface, + ), + ), + ], + ), + ), + if (copyable || onTap != null) + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + copyable ? Icons.copy_rounded : Icons.launch_rounded, + size: 16, + color: theme.colorScheme.primary, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildFeatureChip({ + required String label, + required IconData icon, + required ThemeData theme, + Color? backgroundColor, + Color? textColor, + }) { + final bgColor = + backgroundColor ?? theme.colorScheme.primary.withValues(alpha: 0.08); + final txtColor = textColor ?? theme.colorScheme.primary; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + margin: const EdgeInsets.only(right: 8, bottom: 8), + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: txtColor.withValues(alpha: 0.2), width: 1), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(icon, size: 16, color: txtColor), + const SizedBox(width: 6), + Text( + label, + style: TextStyle( + color: txtColor, + fontSize: 13, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + backgroundColor: theme.colorScheme.surface, + appBar: AppBar( + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: theme.colorScheme.surface, + surfaceTintColor: Colors.transparent, + title: Text( + 'Help & Support', + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + ), + body: ListView( + padding: const EdgeInsets.only(top: 8, bottom: 32), + children: [ + // Welcome Section + RepaintBoundary( + child: Container( + margin: const EdgeInsets.fromLTRB(20, 0, 20, 16), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + theme.colorScheme.primary.withValues(alpha: 0.05), + theme.colorScheme.primary.withValues(alpha: 0.02), + ], + ), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.1), + width: 1, + ), + ), + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + children: [ + // App Icon + Container( + width: 64, + height: 64, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: theme.colorScheme.primary.withValues( + alpha: 0.3, + ), + blurRadius: 16, + offset: const Offset(0, 8), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.asset( + 'assets/icon/icon.png', + width: 64, + height: 64, + fit: BoxFit.cover, + ), + ), + ), + + const SizedBox(height: 16), + + Text( + 'We\'re here to help!', + style: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.w800, + color: theme.colorScheme.onSurface, + ), + ), + + const SizedBox(height: 8), + + Text( + 'Get support for BottleCRM and learn about our open-source project', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.7, + ), + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ), + ), + + // Open Source Information + RepaintBoundary( + child: _buildInfoCard( + title: 'Open Source Project', + icon: Icons.code_rounded, + theme: theme, + children: [ + Container( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.green.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + Icons.verified_rounded, + size: 16, + color: Colors.green, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Text( + 'Open Source CRM', + style: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w700, + color: theme.colorScheme.onSurface, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHighest + .withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline.withValues( + alpha: 0.2, + ), + ), + ), + child: Text( + 'BottleCRM is an open-source CRM solution distributed under the MIT License. This means you have the freedom to use, modify, and distribute the software according to your needs.', + style: theme.textTheme.bodyMedium?.copyWith( + height: 1.5, + color: theme.colorScheme.onSurface.withValues( + alpha: 0.8, + ), + ), + ), + ), + const SizedBox(height: 16), + Wrap( + children: [ + _buildFeatureChip( + label: 'MIT License', + icon: Icons.balance_rounded, + theme: theme, + backgroundColor: Colors.green.withValues( + alpha: 0.1, + ), + textColor: Colors.green, + ), + _buildFeatureChip( + label: 'Free to Use', + icon: Icons.free_breakfast_rounded, + theme: theme, + backgroundColor: Colors.blue.withValues(alpha: 0.1), + textColor: Colors.blue, + ), + _buildFeatureChip( + label: 'Community Driven', + icon: Icons.groups_rounded, + theme: theme, + backgroundColor: Colors.purple.withValues( + alpha: 0.1, + ), + textColor: Colors.purple, + ), + ], + ), + ], + ), + ), + ], + ), + ), + + // Get Support + RepaintBoundary( + child: _buildInfoCard( + title: 'Get Support', + icon: Icons.support_agent_rounded, + theme: theme, + children: [ + _buildInfoRow( + label: 'GitHub Repository', + value: 'github.com/MicroPyramid/opensource-startup-crm', + theme: theme, + leadingIcon: Icons.code_rounded, + onTap: () { + HapticFeedback.lightImpact(); + // TODO: Launch GitHub URL + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Opening GitHub repository...'), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + action: SnackBarAction( + label: 'Copy', + onPressed: () { + Clipboard.setData( + const ClipboardData( + text: + 'https://github.com/MicroPyramid/opensource-startup-crm', + ), + ); + }, + ), + ), + ); + }, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + label: 'Email Support', + value: 'hello@micropyramid.com', + theme: theme, + leadingIcon: Icons.email_rounded, + onTap: () { + HapticFeedback.lightImpact(); + // TODO: Launch email app + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Opening email app...'), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + action: SnackBarAction( + label: 'Copy', + onPressed: () { + Clipboard.setData( + const ClipboardData( + text: 'hello@micropyramid.com', + ), + ); + }, + ), + ), + ); + }, + ), + const SizedBox(height: 8), + ], + ), + ), + + // How to Contribute + RepaintBoundary( + child: _buildInfoCard( + title: 'How to Contribute', + icon: Icons.volunteer_activism_rounded, + theme: theme, + children: [ + Container( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildContributionStep( + stepNumber: '1', + title: 'Report Issues', + description: + 'Found a bug? Report it on our GitHub repository to help us improve.', + icon: Icons.bug_report_rounded, + theme: theme, + ), + const SizedBox(height: 16), + _buildContributionStep( + stepNumber: '2', + title: 'Request Features', + description: + 'Have an idea for a new feature? Share it with the community on GitHub.', + icon: Icons.lightbulb_rounded, + theme: theme, + ), + const SizedBox(height: 16), + _buildContributionStep( + stepNumber: '3', + title: 'Contribute Code', + description: + 'Help improve BottleCRM by contributing code, documentation, or testing.', + icon: Icons.code_rounded, + theme: theme, + ), + ], + ), + ), + ], + ), + ), + + // Contact Information + RepaintBoundary( + child: _buildInfoCard( + title: 'Contact Information', + icon: Icons.contact_support_rounded, + theme: theme, + children: [ + Container( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer.withValues( + alpha: 0.3, + ), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.primary.withValues( + alpha: 0.2, + ), + ), + ), + child: Column( + children: [ + Icon( + Icons.business_center_rounded, + size: 32, + color: theme.colorScheme.primary, + ), + const SizedBox(height: 12), + Text( + 'MicroPyramid', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: theme.colorScheme.onPrimaryContainer, + ), + ), + const SizedBox(height: 4), + Text( + 'Technology Solutions & Open Source Development', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onPrimaryContainer + .withValues(alpha: 0.8), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.language_rounded, + size: 16, + color: theme.colorScheme.onPrimaryContainer + .withValues(alpha: 0.7), + ), + const SizedBox(width: 4), + Text( + 'micropyramid.com', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onPrimaryContainer + .withValues(alpha: 0.7), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildContributionStep({ + required String stepNumber, + required String title, + required String description, + required IconData icon, + required ThemeData theme, + }) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 32, + height: 32, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(16), + ), + child: Center( + child: Text( + stepNumber, + style: theme.textTheme.labelMedium?.copyWith( + color: Colors.white, + fontWeight: FontWeight.w700, + ), + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(icon, size: 20, color: theme.colorScheme.primary), + const SizedBox(width: 8), + Text( + title, + style: theme.textTheme.titleSmall?.copyWith( + fontWeight: FontWeight.w700, + color: theme.colorScheme.onSurface, + ), + ), + ], + ), + const SizedBox(height: 4), + Text( + description, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.7), + height: 1.4, + ), + ), + ], + ), + ), + ], + ); + } +} diff --git a/lib/screens/lead_create_screen.dart b/lib/screens/lead_create_screen.dart new file mode 100644 index 0000000..f3eb53f --- /dev/null +++ b/lib/screens/lead_create_screen.dart @@ -0,0 +1,422 @@ +import 'package:flutter/material.dart'; +import '../services/leads_service.dart'; +import '../models/api_models.dart'; + +class LeadCreateScreen extends StatefulWidget { + const LeadCreateScreen({super.key}); + + @override + State createState() => _LeadCreateScreenState(); +} + +class _LeadCreateScreenState extends State { + final _formKey = GlobalKey(); + final LeadsService _leadsService = LeadsService(); + + // Form controllers + final _firstNameController = TextEditingController(); + final _lastNameController = TextEditingController(); + final _emailController = TextEditingController(); + final _phoneController = TextEditingController(); + final _companyController = TextEditingController(); + final _titleController = TextEditingController(); + final _descriptionController = TextEditingController(); + + // Dropdown values + LeadStatus _selectedStatus = LeadStatus.newLead; + LeadSource _selectedLeadSource = LeadSource.web; + LeadIndustry? _selectedIndustry; + LeadRating? _selectedRating; + + bool _isLoading = false; + + + @override + void dispose() { + _firstNameController.dispose(); + _lastNameController.dispose(); + _emailController.dispose(); + _phoneController.dispose(); + _companyController.dispose(); + _titleController.dispose(); + _descriptionController.dispose(); + super.dispose(); + } + + Future _createLead() async { + if (!_formKey.currentState!.validate()) return; + + setState(() { + _isLoading = true; + }); + + try { + final leadData = { + 'firstName': _firstNameController.text.trim(), + 'lastName': _lastNameController.text.trim(), + 'email': _emailController.text.trim(), + 'phone': _phoneController.text.trim().isEmpty + ? null + : _phoneController.text.trim(), + 'company': _companyController.text.trim().isEmpty + ? null + : _companyController.text.trim(), + 'title': _titleController.text.trim().isEmpty + ? null + : _titleController.text.trim(), + 'status': _selectedStatus.value, + 'leadSource': _selectedLeadSource.value, + 'industry': _selectedIndustry?.value, + 'rating': _selectedRating?.value, + 'description': _descriptionController.text.trim().isEmpty + ? null + : _descriptionController.text.trim(), + }; + + final createdLead = await _leadsService.createLead(leadData); + + if (mounted) { + if (createdLead != null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Lead created successfully!'), + backgroundColor: Colors.green, + ), + ); + Navigator.of(context).pop(true); // Return true to indicate success + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to create lead. Please try again.'), + backgroundColor: Colors.red, + ), + ); + } + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error creating lead: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + appBar: AppBar( + title: const Text('Create Lead'), + elevation: 0, + actions: [ + TextButton( + onPressed: _isLoading ? null : _createLead, + child: _isLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Save'), + ), + ], + ), + body: Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Lead Information section + Text( + 'Lead Information', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(height: 16), + + // Title/Subject of Lead + TextFormField( + controller: _titleController, + decoration: InputDecoration( + labelText: 'Lead Title *', + hintText: 'e.g., VP of Engineering - TechCorp Solutions', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Lead title is required'; + } + return null; + }, + ), + const SizedBox(height: 16), + + // Description + TextFormField( + controller: _descriptionController, + maxLines: 3, + decoration: InputDecoration( + labelText: 'Lead Description *', + hintText: 'Describe the lead opportunity, needs, interests, etc.', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + alignLabelWithHint: true, + ), + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Lead description is required'; + } + return null; + }, + ), + const SizedBox(height: 24), + + // Contact Details section + Text( + 'Contact Details', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(height: 16), + + // First Name + TextFormField( + controller: _firstNameController, + decoration: InputDecoration( + labelText: 'First Name *', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'First name is required'; + } + return null; + }, + ), + const SizedBox(height: 16), + + // Last Name + TextFormField( + controller: _lastNameController, + decoration: InputDecoration( + labelText: 'Last Name *', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Last name is required'; + } + return null; + }, + ), + const SizedBox(height: 16), + + // Email + TextFormField( + controller: _emailController, + keyboardType: TextInputType.emailAddress, + decoration: InputDecoration( + labelText: 'Email *', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Email is required'; + } + if (!RegExp( + r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$', + ).hasMatch(value)) { + return 'Please enter a valid email address'; + } + return null; + }, + ), + const SizedBox(height: 16), + + // Phone + TextFormField( + controller: _phoneController, + keyboardType: TextInputType.phone, + decoration: InputDecoration( + labelText: 'Phone', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + ), + const SizedBox(height: 16), + + // Company + TextFormField( + controller: _companyController, + decoration: InputDecoration( + labelText: 'Company', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + ), + const SizedBox(height: 24), + + // Lead Classification section + Text( + 'Lead Classification', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(height: 16), + + // Status dropdown + DropdownButtonFormField( + value: _selectedStatus, + decoration: InputDecoration( + labelText: 'Status', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + items: LeadStatus.values.map((status) { + return DropdownMenuItem(value: status, child: Text(status.value)); + }).toList(), + onChanged: (value) { + setState(() { + _selectedStatus = value!; + }); + }, + ), + const SizedBox(height: 16), + + // Lead Source dropdown + DropdownButtonFormField( + value: _selectedLeadSource, + decoration: InputDecoration( + labelText: 'Lead Source', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + items: LeadSource.values.map((source) { + return DropdownMenuItem( + value: source, + child: Text(source.displayName), + ); + }).toList(), + onChanged: (value) { + setState(() { + _selectedLeadSource = value!; + }); + }, + ), + const SizedBox(height: 16), + + // Industry dropdown + DropdownButtonFormField( + value: _selectedIndustry, + decoration: InputDecoration( + labelText: 'Industry', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + items: [ + const DropdownMenuItem( + value: null, + child: Text('Select Industry'), + ), + ...LeadIndustry.values.map((industry) { + return DropdownMenuItem( + value: industry, + child: Text(industry.value), + ); + }), + ], + onChanged: (value) { + setState(() { + _selectedIndustry = value; + }); + }, + ), + const SizedBox(height: 16), + + // Rating dropdown + DropdownButtonFormField( + value: _selectedRating, + decoration: InputDecoration( + labelText: 'Rating', + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + items: [ + const DropdownMenuItem( + value: null, + child: Text('Select Rating'), + ), + ...LeadRating.values.map((rating) { + return DropdownMenuItem(value: rating, child: Text(rating.value)); + }), + ], + onChanged: (value) { + setState(() { + _selectedRating = value; + }); + }, + ), + const SizedBox(height: 32), + + // Create button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isLoading ? null : _createLead, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: _isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Create Lead'), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/lead_detail_screen.dart b/lib/screens/lead_detail_screen.dart new file mode 100644 index 0000000..1aed838 --- /dev/null +++ b/lib/screens/lead_detail_screen.dart @@ -0,0 +1,891 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:intl/intl.dart'; +import '../models/api_models.dart'; +import '../services/leads_service.dart'; + +class LeadDetailScreen extends StatefulWidget { + final String leadId; + + const LeadDetailScreen({super.key, required this.leadId}); + + @override + State createState() => _LeadDetailScreenState(); +} + +class _LeadDetailScreenState extends State { + final LeadsService _leadsService = LeadsService(); + Lead? _lead; + bool _isLoading = true; + + @override + void initState() { + super.initState(); + _loadLeadDetails(); + } + + Future _loadLeadDetails() async { + setState(() { + _isLoading = true; + }); + + try { + final lead = await _leadsService.getLeadById(widget.leadId); + if (mounted) { + setState(() { + _lead = lead; + _isLoading = false; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error loading lead details: $e')), + ); + } + } + } + + Color _getStatusColor(String status) { + switch (status.toUpperCase()) { + case 'NEW': + return const Color(0xFF2196F3); // Modern blue + case 'CONTACTED': + return const Color(0xFFFF9800); // Vibrant orange + case 'QUALIFIED': + return const Color(0xFF4CAF50); // Success green + case 'LOST': + return const Color(0xFFE53935); // Error red + case 'PROPOSAL': + return const Color(0xFF9C27B0); // Purple + case 'NEGOTIATION': + return const Color(0xFF607D8B); // Blue grey + default: + return const Color(0xFF757575); // Neutral grey + } + } + + Color _getRatingColor(String? rating) { + switch (rating?.toLowerCase()) { + case 'hot': + return const Color(0xFFE53935); // Hot red + case 'warm': + return const Color(0xFFFF9800); // Warm orange + case 'cold': + return const Color(0xFF2196F3); // Cool blue + default: + return const Color(0xFF757575); // Neutral grey + } + } + + Widget _buildInfoRow({ + required IconData icon, + required String label, + required String? value, + required ThemeData theme, + VoidCallback? onTap, + }) { + if (value == null || value.isEmpty) { + return const SizedBox.shrink(); + } + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(10), + ), + child: Icon(icon, size: 20, color: theme.colorScheme.primary), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: theme.textTheme.labelMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues( + alpha: 0.7, + ), + fontWeight: FontWeight.w500, + letterSpacing: 0.5, + ), + ), + const SizedBox(height: 4), + Text( + value, + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w600, + height: 1.2, + ), + ), + ], + ), + ), + if (onTap != null) + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + Icons.launch, + size: 16, + color: theme.colorScheme.primary, + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildStatusChip(String status, ThemeData theme) { + final statusColor = _getStatusColor(status); + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: statusColor.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: statusColor.withValues(alpha: 0.3), + width: 1.5, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: statusColor, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 8), + Text( + status.toUpperCase(), + style: TextStyle( + color: statusColor, + fontSize: 13, + fontWeight: FontWeight.w700, + letterSpacing: 0.5, + ), + ), + ], + ), + ); + } + + Widget _buildRatingChip(String rating, ThemeData theme) { + final ratingColor = _getRatingColor(rating); + return Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), + decoration: BoxDecoration( + color: ratingColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(18), + border: Border.all( + color: ratingColor.withValues(alpha: 0.3), + width: 1.5, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.local_fire_department_rounded, + size: 16, + color: ratingColor, + ), + const SizedBox(width: 6), + Text( + rating.toUpperCase(), + style: TextStyle( + color: ratingColor, + fontSize: 13, + fontWeight: FontWeight.w700, + letterSpacing: 0.3, + ), + ), + ], + ), + ); + } + + Widget _buildSectionCard({ + required String title, + required List children, + required ThemeData theme, + IconData? icon, + }) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), + decoration: BoxDecoration( + color: theme.colorScheme.surface, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outline.withValues(alpha: 0.08), + width: 1, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.02), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: Row( + children: [ + if (icon != null) ...[ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + ), + child: Icon( + icon, + size: 20, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 12), + ], + Text( + title, + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: theme.colorScheme.onSurface, + letterSpacing: 0.3, + ), + ), + ], + ), + ), + ...children, + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + backgroundColor: theme.colorScheme.surface, + extendBodyBehindAppBar: false, + appBar: AppBar( + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: theme.colorScheme.surface, + surfaceTintColor: Colors.transparent, + title: Text( + _lead?.fullName ?? 'Lead Details', + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + actions: [ + if (_lead != null) ...[ + Container( + margin: const EdgeInsets.only(right: 8), + child: IconButton.filledTonal( + icon: const Icon(Icons.edit_rounded), + onPressed: () { + HapticFeedback.lightImpact(); + // TODO: Navigate to edit lead screen + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Edit functionality coming soon'), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ); + }, + ), + ), + if (!(_lead?.isConverted ?? false)) + Container( + margin: const EdgeInsets.only(right: 12), + child: IconButton.filled( + icon: const Icon(Icons.transform_rounded), + tooltip: 'Convert Lead', + onPressed: () { + HapticFeedback.mediumImpact(); + // TODO: Implement convert lead functionality + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text( + 'Convert functionality coming soon', + ), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ); + }, + ), + ), + ], + ], + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _lead == null + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: theme.colorScheme.errorContainer.withValues( + alpha: 0.1, + ), + shape: BoxShape.circle, + ), + child: Icon( + Icons.person_off_rounded, + size: 64, + color: theme.colorScheme.error.withValues(alpha: 0.6), + ), + ), + const SizedBox(height: 24), + Text( + 'Lead not found', + style: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.w600, + color: theme.colorScheme.onSurface.withValues(alpha: 0.8), + ), + ), + const SizedBox(height: 8), + Text( + 'The lead you\'re looking for doesn\'t exist or has been removed.', + textAlign: TextAlign.center, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface.withValues(alpha: 0.6), + ), + ), + const SizedBox(height: 24), + FilledButton.icon( + onPressed: _loadLeadDetails, + icon: const Icon(Icons.refresh_rounded), + label: const Text('Try Again'), + ), + ], + ), + ) + : RefreshIndicator( + onRefresh: _loadLeadDetails, + child: ListView( + padding: const EdgeInsets.only(top: 8, bottom: 32), + children: [ + // Hero Header Card + RepaintBoundary( + child: Container( + margin: const EdgeInsets.fromLTRB(20, 0, 20, 16), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withValues( + alpha: 0.03, + ), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: theme.colorScheme.outline.withValues( + alpha: 0.1, + ), + width: 1, + ), + ), + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Avatar and Status Row + Row( + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(16), + ), + child: Center( + child: Text( + _lead!.fullName.isNotEmpty + ? _lead!.fullName + .split(' ') + .map( + (n) => + n.isNotEmpty ? n[0] : '', + ) + .take(2) + .join() + .toUpperCase() + : 'L', + style: theme.textTheme.titleLarge + ?.copyWith( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + _lead!.fullName, + style: theme.textTheme.headlineSmall + ?.copyWith( + fontWeight: FontWeight.w800, + height: 1.1, + ), + ), + if (_lead!.title != null) ...[ + const SizedBox(height: 4), + Text( + _lead!.title!, + style: theme.textTheme.bodyLarge + ?.copyWith( + color: + theme.colorScheme.primary, + fontWeight: FontWeight.w600, + ), + ), + ], + if (_lead!.company != null) ...[ + const SizedBox(height: 2), + Row( + children: [ + Icon( + Icons.business_rounded, + size: 16, + color: theme.colorScheme.onSurface + .withValues(alpha: 0.6), + ), + const SizedBox(width: 4), + Flexible( + child: Text( + _lead!.company!, + style: theme + .textTheme + .bodyMedium + ?.copyWith( + color: theme + .colorScheme + .onSurface + .withValues( + alpha: 0.7, + ), + fontWeight: + FontWeight.w500, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ], + ], + ), + ), + _buildStatusChip(_lead!.status, theme), + ], + ), + + const SizedBox(height: 20), + + // Rating and Source Row + Row( + children: [ + if (_lead!.rating != null) ...[ + _buildRatingChip(_lead!.rating!, theme), + const SizedBox(width: 12), + ], + Expanded( + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + decoration: BoxDecoration( + color: theme + .colorScheme + .surfaceContainerHighest + .withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline + .withValues(alpha: 0.2), + ), + ), + child: Row( + children: [ + Icon( + Icons.source_rounded, + size: 16, + color: theme + .colorScheme + .onSurfaceVariant, + ), + const SizedBox(width: 8), + Flexible( + child: Text( + _lead!.leadSource, + style: theme.textTheme.bodySmall + ?.copyWith( + color: theme + .colorScheme + .onSurfaceVariant, + fontWeight: FontWeight.w600, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ), + ], + ), + + // Converted Status + if (_lead!.isConverted) ...[ + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + decoration: BoxDecoration( + color: Colors.green.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: Colors.green.withValues(alpha: 0.3), + ), + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: Colors.green.withValues( + alpha: 0.15, + ), + borderRadius: BorderRadius.circular(8), + ), + child: const Icon( + Icons.check_circle_rounded, + color: Colors.green, + size: 20, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + const Text( + 'Successfully Converted', + style: TextStyle( + color: Colors.green, + fontSize: 14, + fontWeight: FontWeight.w700, + ), + ), + if (_lead!.convertedAt != null) + Text( + DateFormat( + 'MMM dd, yyyy • HH:mm', + ).format(_lead!.convertedAt!), + style: TextStyle( + color: Colors.green.withValues( + alpha: 0.8, + ), + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ], + ), + ), + ), + ), + + // Contact Information + RepaintBoundary( + child: _buildSectionCard( + title: 'Contact Information', + icon: Icons.contact_phone_rounded, + theme: theme, + children: [ + _buildInfoRow( + icon: Icons.email_rounded, + label: 'Email Address', + value: _lead!.email, + theme: theme, + onTap: _lead!.email != null + ? () { + HapticFeedback.lightImpact(); + // TODO: Launch email app + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Email: ${_lead!.email}'), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ); + } + : null, + ), + if (_lead!.email != null && _lead!.phone != null) + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + icon: Icons.phone_rounded, + label: 'Phone Number', + value: _lead!.phone, + theme: theme, + onTap: _lead!.phone != null + ? () { + HapticFeedback.lightImpact(); + // TODO: Launch phone app + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Phone: ${_lead!.phone}'), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ); + } + : null, + ), + const SizedBox(height: 8), + ], + ), + ), + + // Additional Information + if (_lead!.industry != null || _lead!.description != null) + RepaintBoundary( + child: _buildSectionCard( + title: 'Additional Information', + icon: Icons.info_rounded, + theme: theme, + children: [ + _buildInfoRow( + icon: Icons.business_center_rounded, + label: 'Industry', + value: _lead!.industry, + theme: theme, + ), + if (_lead!.industry != null && + _lead!.description != null) + Container( + height: 1, + margin: const EdgeInsets.symmetric( + horizontal: 20, + ), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + if (_lead!.description != null) + Container( + padding: const EdgeInsets.symmetric( + vertical: 16, + horizontal: 20, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: theme.colorScheme.primary + .withValues(alpha: 0.08), + borderRadius: BorderRadius.circular( + 10, + ), + ), + child: Icon( + Icons.description_rounded, + size: 20, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(width: 16), + Text( + 'Description', + style: theme.textTheme.labelMedium + ?.copyWith( + color: theme.colorScheme.onSurface + .withValues(alpha: 0.7), + fontWeight: FontWeight.w500, + letterSpacing: 0.5, + ), + ), + ], + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: theme + .colorScheme + .surfaceContainerHighest + .withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.outline + .withValues(alpha: 0.2), + ), + ), + child: Text( + _lead!.description!, + style: theme.textTheme.bodyMedium + ?.copyWith( + height: 1.5, + color: theme.colorScheme.onSurface + .withValues(alpha: 0.8), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 8), + ], + ), + ), + + // Owner Information + if (_lead!.owner != null) + RepaintBoundary( + child: _buildSectionCard( + title: 'Lead Owner', + icon: Icons.person_rounded, + theme: theme, + children: [ + _buildInfoRow( + icon: Icons.account_circle_rounded, + label: 'Name', + value: _lead!.owner!.name, + theme: theme, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + icon: Icons.alternate_email_rounded, + label: 'Email Address', + value: _lead!.owner!.email, + theme: theme, + onTap: () { + HapticFeedback.lightImpact(); + // TODO: Launch email app + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Owner Email: ${_lead!.owner!.email}', + ), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ); + }, + ), + const SizedBox(height: 8), + ], + ), + ), + + // Timeline Information + RepaintBoundary( + child: _buildSectionCard( + title: 'Timeline', + icon: Icons.schedule_rounded, + theme: theme, + children: [ + _buildInfoRow( + icon: Icons.add_circle_outline_rounded, + label: 'Created', + value: DateFormat( + 'MMM dd, yyyy • HH:mm', + ).format(_lead!.createdAt), + theme: theme, + ), + Container( + height: 1, + margin: const EdgeInsets.symmetric(horizontal: 20), + color: theme.dividerColor.withValues(alpha: 0.3), + ), + _buildInfoRow( + icon: Icons.update_rounded, + label: 'Last Updated', + value: DateFormat( + 'MMM dd, yyyy • HH:mm', + ).format(_lead!.updatedAt), + theme: theme, + ), + const SizedBox(height: 8), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/leads_list_screen.dart b/lib/screens/leads_list_screen.dart new file mode 100644 index 0000000..8e44679 --- /dev/null +++ b/lib/screens/leads_list_screen.dart @@ -0,0 +1,837 @@ +import 'package:flutter/material.dart'; +import '../models/api_models.dart'; +import '../services/leads_service.dart'; + +class LeadsListScreen extends StatefulWidget { + const LeadsListScreen({super.key}); + + @override + State createState() => _LeadsListScreenState(); +} + +class _LeadsListScreenState extends State { + final LeadsService _leadsService = LeadsService(); + final ScrollController _scrollController = ScrollController(); + final TextEditingController _searchController = TextEditingController(); + + List _leads = []; + bool _isLoading = true; + bool _isLoadingMore = false; + bool _hasError = false; + bool _isSearching = false; + String? _errorMessage; + int _currentPage = 1; + bool _hasMoreData = true; + + String? _selectedStatus; + String? _selectedSource; + String? _selectedRating; + String? _selectedIndustry; + bool? _selectedConverted; + + @override + void initState() { + super.initState(); + _loadLeads(); + _scrollController.addListener(_onScroll); + } + + @override + void dispose() { + _scrollController.dispose(); + _searchController.dispose(); + super.dispose(); + } + + void _onScroll() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + if (!_isLoadingMore && _hasMoreData && !_isSearching) { + _loadMoreLeads(); + } + } + } + + Future _loadLeads({bool isRefresh = false}) async { + debugPrint('Loading leads - refresh: $isRefresh'); + if (isRefresh) { + setState(() { + _currentPage = 1; + _hasMoreData = true; + _isLoading = true; + _hasError = false; + }); + } + + try { + final response = await _leadsService.getLeads( + page: _currentPage, + status: _selectedStatus, + leadSource: _selectedSource, + rating: _selectedRating, + industry: _selectedIndustry, + converted: _selectedConverted, + searchQuery: _searchController.text.isNotEmpty + ? _searchController.text + : null, + ); + + if (response != null) { + setState(() { + if (isRefresh || _currentPage == 1) { + _leads = response.leads; + } else { + _leads.addAll(response.leads); + } + _hasMoreData = response.pagination.hasNext; + _isLoading = false; + _hasError = false; + _isSearching = false; + }); + } else { + setState(() { + _hasError = true; + _errorMessage = 'Failed to load leads'; + _isLoading = false; + _isSearching = false; + }); + } + } catch (e) { + setState(() { + _hasError = true; + _errorMessage = e.toString(); + _isLoading = false; + _isSearching = false; + }); + } + } + + Future _loadMoreLeads() async { + if (_isLoadingMore || !_hasMoreData) return; + + setState(() { + _isLoadingMore = true; + }); + + _currentPage++; + + try { + final response = await _leadsService.getLeads( + page: _currentPage, + status: _selectedStatus, + leadSource: _selectedSource, + rating: _selectedRating, + industry: _selectedIndustry, + converted: _selectedConverted, + searchQuery: _searchController.text.isNotEmpty + ? _searchController.text + : null, + ); + + if (response != null) { + setState(() { + _leads.addAll(response.leads); + _hasMoreData = response.pagination.hasNext; + _isLoadingMore = false; + }); + } else { + setState(() { + _isLoadingMore = false; + _currentPage--; + }); + } + } catch (e) { + setState(() { + _isLoadingMore = false; + _currentPage--; + }); + } + } + + Future _onRefresh() async { + await _loadLeads(isRefresh: true); + } + + void _onSearchChanged() { + setState(() { + _isSearching = true; + }); + _loadLeads(isRefresh: true); + } + + void _showFilterDialog() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Filter Leads'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + DropdownButtonFormField( + value: _selectedStatus, + decoration: const InputDecoration( + labelText: 'Status', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem(value: null, child: Text('All Statuses')), + DropdownMenuItem(value: 'NEW', child: Text('New')), + DropdownMenuItem(value: 'PENDING', child: Text('Pending')), + DropdownMenuItem(value: 'CONTACTED', child: Text('Contacted')), + DropdownMenuItem(value: 'QUALIFIED', child: Text('Qualified')), + DropdownMenuItem(value: 'UNQUALIFIED', child: Text('Unqualified')), + DropdownMenuItem(value: 'CONVERTED', child: Text('Converted')), + ], + onChanged: (value) { + setState(() { + _selectedStatus = value; + }); + }, + ), + const SizedBox(height: 16), + DropdownButtonFormField( + value: _selectedSource, + decoration: const InputDecoration( + labelText: 'Lead Source', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem(value: null, child: Text('All Sources')), + DropdownMenuItem(value: 'WEB', child: Text('Web')), + DropdownMenuItem(value: 'PHONE_INQUIRY', child: Text('Phone Inquiry')), + DropdownMenuItem(value: 'PARTNER_REFERRAL', child: Text('Partner Referral')), + DropdownMenuItem(value: 'COLD_CALL', child: Text('Cold Call')), + DropdownMenuItem(value: 'TRADE_SHOW', child: Text('Trade Show')), + DropdownMenuItem(value: 'EMPLOYEE_REFERRAL', child: Text('Employee Referral')), + DropdownMenuItem(value: 'ADVERTISEMENT', child: Text('Advertisement')), + DropdownMenuItem(value: 'OTHER', child: Text('Other')), + ], + onChanged: (value) { + setState(() { + _selectedSource = value; + }); + }, + ), + const SizedBox(height: 16), + DropdownButtonFormField( + value: _selectedRating, + decoration: const InputDecoration( + labelText: 'Rating', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem(value: null, child: Text('All Ratings')), + DropdownMenuItem(value: 'Hot', child: Text('Hot')), + DropdownMenuItem(value: 'Warm', child: Text('Warm')), + DropdownMenuItem(value: 'Cold', child: Text('Cold')), + ], + onChanged: (value) { + setState(() { + _selectedRating = value; + }); + }, + ), + const SizedBox(height: 16), + DropdownButtonFormField( + value: _selectedIndustry, + decoration: const InputDecoration( + labelText: 'Industry', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem(value: null, child: Text('All Industries')), + DropdownMenuItem(value: 'Technology', child: Text('Technology')), + DropdownMenuItem(value: 'Healthcare', child: Text('Healthcare')), + DropdownMenuItem(value: 'Finance', child: Text('Finance')), + DropdownMenuItem(value: 'Education', child: Text('Education')), + DropdownMenuItem(value: 'Manufacturing', child: Text('Manufacturing')), + DropdownMenuItem(value: 'Retail', child: Text('Retail')), + DropdownMenuItem(value: 'Real Estate', child: Text('Real Estate')), + DropdownMenuItem(value: 'Consulting', child: Text('Consulting')), + DropdownMenuItem(value: 'Media', child: Text('Media')), + DropdownMenuItem(value: 'Transportation', child: Text('Transportation')), + DropdownMenuItem(value: 'Energy', child: Text('Energy')), + DropdownMenuItem(value: 'Government', child: Text('Government')), + DropdownMenuItem(value: 'Non-profit', child: Text('Non-profit')), + DropdownMenuItem(value: 'Other', child: Text('Other')), + ], + onChanged: (value) { + setState(() { + _selectedIndustry = value; + }); + }, + ), + const SizedBox(height: 16), + DropdownButtonFormField( + value: _selectedConverted, + decoration: const InputDecoration( + labelText: 'Converted', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem(value: null, child: Text('All')), + DropdownMenuItem(value: false, child: Text('Not Converted')), + DropdownMenuItem(value: true, child: Text('Converted')), + ], + onChanged: (value) { + setState(() { + _selectedConverted = value; + }); + }, + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () { + setState(() { + _selectedStatus = null; + _selectedSource = null; + _selectedRating = null; + _selectedIndustry = null; + _selectedConverted = null; + }); + Navigator.pop(context); + _loadLeads(isRefresh: true); + }, + child: const Text('Clear'), + ), + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + _loadLeads(isRefresh: true); + }, + child: const Text('Apply'), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Leads'), + actions: [ + IconButton( + icon: const Icon(Icons.filter_list), + onPressed: _showFilterDialog, + ), + ], + ), + body: Column( + children: [ + Container( + padding: const EdgeInsets.all(16), + color: Colors.white, + child: TextField( + controller: _searchController, + decoration: InputDecoration( + hintText: 'Search leads by name, email, or company...', + prefixIcon: const Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Colors.grey.shade300), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + filled: true, + fillColor: Colors.grey.shade50, + suffixIcon: _searchController.text.isNotEmpty + ? IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _searchController.clear(); + _onSearchChanged(); + }, + ) + : null, + ), + onChanged: (_) => _onSearchChanged(), + ), + ), + Expanded( + child: RefreshIndicator( + onRefresh: _onRefresh, + child: _buildContent(), + ), + ), + ], + ), + floatingActionButton: FloatingActionButton( + heroTag: "leads_fab", + onPressed: () async { + final result = await Navigator.of(context).pushNamed('/lead-create'); + if (result == true) { + _loadLeads(isRefresh: true); + } + }, + child: const Icon(Icons.add), + ), + ); + } + + Widget _buildContent() { + if (_isLoading && _leads.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: const [ + SizedBox(height: 200), + Center(child: CircularProgressIndicator()), + ], + ); + } + + if (_hasError && _leads.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.3), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + _errorMessage ?? 'Something went wrong', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () => _loadLeads(isRefresh: true), + child: const Text('Retry'), + ), + ], + ), + ), + ], + ); + } + + if (_leads.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.3), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.people_outline, + size: 64, + color: Colors.grey[400], + ), + const SizedBox(height: 16), + Text( + 'No leads found', + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 8), + Text( + 'Add your first lead to get started', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: Colors.grey[600]), + ), + ], + ), + ), + ], + ); + } + + return ListView.builder( + controller: _scrollController, + physics: const AlwaysScrollableScrollPhysics(), + itemCount: _leads.length + (_isLoadingMore ? 1 : 0), + itemBuilder: (context, index) { + if (index == _leads.length) { + return const Center( + child: Padding( + padding: EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), + ); + } + + final lead = _leads[index]; + return _buildLeadCard(lead); + }, + ); + } + + Widget _buildLeadCard(Lead lead) { + Color statusColor = _getStatusColor(lead.status); + Color ratingColor = _getRatingColor(lead.rating); + + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + color: Colors.white, + border: Border( + left: BorderSide(color: statusColor, width: 3), + bottom: BorderSide(color: Colors.grey.shade200, width: 1), + ), + ), + child: ListTile( + contentPadding: const EdgeInsets.all(16), + leading: CircleAvatar( + backgroundColor: Theme.of(context).colorScheme.primary, + child: Text( + lead.firstName.isNotEmpty ? lead.firstName[0].toUpperCase() : '?', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ), + title: Row( + children: [ + Expanded( + child: Text( + lead.title ?? 'Untitled Lead', + style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16), + ), + ), + if (lead.rating != null) + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration( + color: ratingColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: ratingColor.withValues(alpha: 0.3)), + ), + child: Text( + lead.rating!, + style: TextStyle( + color: ratingColor, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (lead.description != null) ...[ + const SizedBox(height: 4), + Text( + lead.description!, + style: TextStyle( + color: Colors.grey[700], + fontSize: 14, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + if (lead.company != null) ...[ + const SizedBox(height: 4), + Row( + children: [ + Icon(Icons.business_outlined, size: 16, color: Colors.grey[600]), + const SizedBox(width: 4), + Expanded( + child: Text( + lead.company!, + style: TextStyle( + color: Colors.grey[600], + fontSize: 13, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + ], + const SizedBox(height: 4), + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration( + color: statusColor.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + _getStatusDisplayName(lead.status), + style: TextStyle( + color: statusColor, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ), + if (lead.owner != null) ...[ + const SizedBox(height: 4), + Text( + 'Owner: ${lead.owner!.fullName}', + style: TextStyle( + color: Colors.grey[500], + fontSize: 12, + fontStyle: FontStyle.italic, + ), + ), + ], + ], + ), + trailing: IconButton( + icon: const Icon(Icons.more_vert), + onPressed: () { + _showLeadOptions(context, lead); + }, + ), + onTap: () { + Navigator.of(context).pushNamed('/lead-detail', arguments: lead.id); + }, + ), + ); + } + + Color _getStatusColor(String status) { + switch (status.toUpperCase()) { + case 'NEW': + return Colors.blue; + case 'PENDING': + return Colors.orange; + case 'CONTACTED': + return Colors.purple; + case 'QUALIFIED': + return Colors.green; + case 'UNQUALIFIED': + return Colors.red; + case 'CONVERTED': + return Colors.teal; + default: + return Colors.grey; + } + } + + Color _getRatingColor(String? rating) { + if (rating == null) return Colors.grey; + switch (rating.toLowerCase()) { + case 'hot': + return Colors.red; + case 'warm': + return Colors.orange; + case 'cold': + return Colors.blue; + default: + return Colors.grey; + } + } + + String _getStatusDisplayName(String status) { + switch (status.toUpperCase()) { + case 'NEW': + return 'New'; + case 'PENDING': + return 'Pending'; + case 'CONTACTED': + return 'Contacted'; + case 'QUALIFIED': + return 'Qualified'; + case 'UNQUALIFIED': + return 'Unqualified'; + case 'CONVERTED': + return 'Converted'; + default: + return status; + } + } + + void _showLeadOptions(BuildContext context, Lead lead) { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.visibility), + title: const Text('View Details'), + onTap: () { + Navigator.pop(context); + Navigator.of(context).pushNamed('/lead-detail', arguments: lead.id); + }, + ), + ListTile( + leading: const Icon(Icons.edit), + title: const Text('Edit Lead'), + onTap: () { + Navigator.pop(context); + // TODO: Navigate to edit lead + }, + ), + if (!lead.isConverted) + ListTile( + leading: const Icon(Icons.transform), + title: const Text('Convert Lead'), + onTap: () { + Navigator.pop(context); + _showConvertDialog(context, lead); + }, + ), + ListTile( + leading: const Icon(Icons.delete, color: Colors.red), + title: const Text( + 'Delete Lead', + style: TextStyle(color: Colors.red), + ), + onTap: () { + Navigator.pop(context); + _showDeleteConfirmation(context, lead); + }, + ), + ], + ), + ); + }, + ); + } + + void _showConvertDialog(BuildContext context, Lead lead) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Convert Lead'), + content: Text( + 'Convert ${lead.fullName} to a contact and account? This action cannot be undone.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + _convertLead(lead); + }, + child: const Text('Convert'), + ), + ], + ); + }, + ); + } + + void _showDeleteConfirmation(BuildContext context, Lead lead) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Delete Lead'), + content: Text( + 'Are you sure you want to delete ${lead.fullName}? This action cannot be undone.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + _deleteLead(lead); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Delete'), + ), + ], + ); + }, + ); + } + + Future _convertLead(Lead lead) async { + final success = await _leadsService.convertLead(lead.id, { + 'createContact': true, + 'createAccount': true, + }); + + if (success) { + setState(() { + final index = _leads.indexWhere((l) => l.id == lead.id); + if (index != -1) { + _leads[index] = Lead( + id: lead.id, + firstName: lead.firstName, + lastName: lead.lastName, + email: lead.email, + phone: lead.phone, + company: lead.company, + title: lead.title, + status: 'CONVERTED', + leadSource: lead.leadSource, + industry: lead.industry, + rating: lead.rating, + description: lead.description, + createdAt: lead.createdAt, + updatedAt: DateTime.now(), + ownerId: lead.ownerId, + organizationId: lead.organizationId, + isConverted: true, + convertedAt: DateTime.now(), + convertedAccountId: lead.convertedAccountId, + convertedContactId: lead.convertedContactId, + convertedOpportunityId: lead.convertedOpportunityId, + contactId: lead.contactId, + owner: lead.owner, + ); + } + }); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('${lead.fullName} converted successfully')), + ); + } + } else { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Failed to convert lead')), + ); + } + } + } + + Future _deleteLead(Lead lead) async { + final success = await _leadsService.deleteLead(lead.id); + + if (success) { + setState(() { + _leads.removeWhere((l) => l.id == lead.id); + }); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('${lead.fullName} deleted successfully')), + ); + } + } else { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Failed to delete lead')), + ); + } + } + } +} \ No newline at end of file diff --git a/lib/screens/login_screen.dart b/lib/screens/login_screen.dart new file mode 100644 index 0000000..48b8832 --- /dev/null +++ b/lib/screens/login_screen.dart @@ -0,0 +1,422 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import '../services/auth_service.dart'; + +class LoginScreen extends StatefulWidget { + const LoginScreen({super.key}); + + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + final AuthService _authService = AuthService(); + bool _isLoading = false; + String? _errorMessage; + String _version = ''; + String _buildNumber = ''; + + @override + void initState() { + super.initState(); + _loadPackageInfo(); + } + + Future _loadPackageInfo() async { + final packageInfo = await PackageInfo.fromPlatform(); + setState(() { + _version = packageInfo.version; + _buildNumber = packageInfo.buildNumber; + }); + } + + Future _signInWithGoogle() async { + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + final success = await _authService.signInWithGoogle(); + + if (success && mounted) { + Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false); + } else if (mounted) { + setState(() { + _errorMessage = 'Failed to sign in with Google. Please try again.'; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _errorMessage = 'An error occurred: ${e.toString()}'; + }); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + Widget _buildFeatureItem(IconData icon, String label, ThemeData theme) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: const Color(0xFF1565C0).withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xFF1565C0).withValues(alpha: 0.15), + width: 1, + ), + ), + child: Icon(icon, size: 24, color: const Color(0xFF1565C0)), + ), + const SizedBox(height: 8), + Text( + label, + style: theme.textTheme.bodySmall?.copyWith( + color: const Color(0xFF424242), + fontWeight: FontWeight.w500, + ), + ), + ], + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + backgroundColor: Colors.white, + body: Container( + width: double.infinity, + height: double.infinity, + child: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Spacer(flex: 1), + + // App Logo + Container( + width: 120, + height: 120, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 16, + offset: const Offset(0, 4), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(24), + child: Image.asset( + 'assets/icon/icon.png', + width: 120, + height: 120, + fit: BoxFit.cover, + ), + ), + ), + + const SizedBox(height: 40), + + // Professional Title with tagline + Column( + children: [ + Text( + 'BottleCRM', + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.w700, + color: const Color(0xFF1A1A1A), + letterSpacing: -1.2, + fontSize: 36, + ), + ), + + const SizedBox(height: 4), + + Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 6, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + const Color(0xFF1565C0).withValues(alpha: 0.1), + const Color(0xFF2196F3).withValues(alpha: 0.05), + ], + ), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: const Color(0xFF1565C0).withValues(alpha: 0.2), + width: 1, + ), + ), + child: Text( + 'PROFESSIONAL EDITION', + style: theme.textTheme.labelSmall?.copyWith( + color: const Color(0xFF1565C0), + fontWeight: FontWeight.w600, + letterSpacing: 1.2, + ), + ), + ), + ], + ), + + const SizedBox(height: 16), + + // Error Message + if (_errorMessage != null) ...[ + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + margin: const EdgeInsets.only(bottom: 24), + decoration: BoxDecoration( + color: theme.colorScheme.errorContainer, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Icon( + Icons.error_outline, + color: theme.colorScheme.onErrorContainer, + size: 20, + ), + const SizedBox(width: 12), + Expanded( + child: Text( + _errorMessage!, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onErrorContainer, + ), + ), + ), + ], + ), + ), + ], + + // Professional Feature Highlights + Container( + padding: const EdgeInsets.all(24), + margin: const EdgeInsets.only(bottom: 32), + decoration: BoxDecoration( + color: const Color(0xFFFAFAFA), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: const Color(0xFFE0E0E0), + width: 1, + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildFeatureItem( + Icons.people_outline, + 'Contacts', + theme, + ), + _buildFeatureItem(Icons.trending_up, 'Analytics', theme), + _buildFeatureItem(Icons.task_alt, 'Pipeline', theme), + ], + ), + ), + + // Google Sign In Button + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Container( + width: double.infinity, + height: 60, + constraints: const BoxConstraints( + maxWidth: 400, // Maximum width for larger screens + ), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: ElevatedButton.icon( + onPressed: _isLoading ? null : _signInWithGoogle, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: const Color(0xFF1A1A1A), + elevation: 0, + shadowColor: Colors.transparent, + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 16, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + side: BorderSide( + color: const Color( + 0xFF1565C0, + ).withValues(alpha: 0.2), + width: 1.5, + ), + ), + ), + icon: _isLoading + ? SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2.5, + valueColor: const AlwaysStoppedAnimation( + Color(0xFF1565C0), + ), + ), + ) + : const FaIcon( + FontAwesomeIcons.google, + size: 20, + color: Color(0xFF4285F4), + ), + label: Text( + _isLoading + ? 'Signing you in...' + : 'Sign in with Google', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: _isLoading + ? const Color(0xFF666666) + : const Color(0xFF1A1A1A), + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), + ), + ), + + const SizedBox(height: 32), + + // Professional Footer + Column( + children: [ + // Security Badge + Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + decoration: BoxDecoration( + color: const Color(0xFF4CAF50).withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: const Color(0xFF4CAF50).withValues(alpha: 0.3), + width: 1, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.security, + size: 16, + color: const Color(0xFF4CAF50), + ), + const SizedBox(width: 6), + Text( + 'Enterprise-grade security', + style: theme.textTheme.bodySmall?.copyWith( + color: const Color(0xFF4CAF50), + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + + const SizedBox(height: 16), + + // Terms and Privacy + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: theme.textTheme.bodySmall?.copyWith( + color: const Color(0xFF666666), + height: 1.5, + fontSize: 12, + ), + children: [ + const TextSpan( + text: 'By signing in, you agree to our ', + ), + TextSpan( + text: 'Terms of Service', + style: TextStyle( + color: const Color(0xFF1565C0), + fontWeight: FontWeight.w500, + decoration: TextDecoration.underline, + decorationColor: const Color( + 0xFF1565C0, + ).withValues(alpha: 0.5), + ), + ), + const TextSpan(text: ' and '), + TextSpan( + text: 'Privacy Policy', + style: TextStyle( + color: const Color(0xFF1565C0), + fontWeight: FontWeight.w500, + decoration: TextDecoration.underline, + decorationColor: const Color( + 0xFF1565C0, + ).withValues(alpha: 0.5), + ), + ), + ], + ), + ), + ), + ], + ), + + const SizedBox(height: 24), + + // Version information + if (_version.isNotEmpty && _buildNumber.isNotEmpty) + Text( + 'Version $_version ($_buildNumber)', + style: theme.textTheme.bodySmall?.copyWith( + color: const Color(0xFF999999), + fontSize: 11, + ), + ), + + const Spacer(flex: 1), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/screens/task_create_screen.dart b/lib/screens/task_create_screen.dart new file mode 100644 index 0000000..981555f --- /dev/null +++ b/lib/screens/task_create_screen.dart @@ -0,0 +1,509 @@ +import 'package:flutter/material.dart'; +import '../services/tasks_service.dart'; +import '../models/api_models.dart'; + +class TaskCreateScreen extends StatefulWidget { + const TaskCreateScreen({super.key}); + + @override + State createState() => _TaskCreateScreenState(); +} + +class _TaskCreateScreenState extends State { + final GlobalKey _formKey = GlobalKey(); + final TasksService _tasksService = TasksService(); + + // Form controllers + final TextEditingController _subjectController = TextEditingController(); + final TextEditingController _descriptionController = TextEditingController(); + final TextEditingController _accountIdController = TextEditingController(); + final TextEditingController _contactIdController = TextEditingController(); + + bool _isLoading = false; + TaskStatus _selectedStatus = TaskStatus.notStarted; + TaskPriority _selectedPriority = TaskPriority.normal; + DateTime? _selectedDueDate; + TimeOfDay? _selectedTime; + + @override + void dispose() { + _subjectController.dispose(); + _descriptionController.dispose(); + _accountIdController.dispose(); + _contactIdController.dispose(); + super.dispose(); + } + + Future _createTask() async { + if (!_formKey.currentState!.validate()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + DateTime? dueDateTime; + if (_selectedDueDate != null) { + // Combine date and time + final time = _selectedTime ?? const TimeOfDay(hour: 9, minute: 0); + dueDateTime = DateTime( + _selectedDueDate!.year, + _selectedDueDate!.month, + _selectedDueDate!.day, + time.hour, + time.minute, + ); + } + + final task = await _tasksService.createTask( + subject: _subjectController.text.trim(), + description: _descriptionController.text.trim().isEmpty + ? null + : _descriptionController.text.trim(), + status: _selectedStatus.value, + priority: _selectedPriority.value, + dueDate: dueDateTime, + accountId: _accountIdController.text.trim().isEmpty + ? null + : _accountIdController.text.trim(), + contactId: _contactIdController.text.trim().isEmpty + ? null + : _contactIdController.text.trim(), + ); + + if (task != null && mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Task "${task.subject}" created successfully'), + backgroundColor: Colors.green, + ), + ); + Navigator.of(context).pop(true); // Return true to indicate success + } else if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to create task'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error creating task: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + String? _validateRequired(String? value, String fieldName) { + if (value == null || value.trim().isEmpty) { + return '$fieldName is required'; + } + return null; + } + + Future _selectDate() async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: + _selectedDueDate ?? DateTime.now().add(const Duration(days: 1)), + firstDate: DateTime.now(), + lastDate: DateTime.now().add(const Duration(days: 365)), + builder: (context, child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: Theme.of(context).colorScheme.copyWith( + primary: Theme.of(context).colorScheme.primary, + ), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + setState(() { + _selectedDueDate = picked; + }); + } + } + + Future _selectTime() async { + if (_selectedDueDate == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Please select a due date first')), + ); + return; + } + + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: _selectedTime ?? const TimeOfDay(hour: 9, minute: 0), + builder: (context, child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: Theme.of(context).colorScheme.copyWith( + primary: Theme.of(context).colorScheme.primary, + ), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + setState(() { + _selectedTime = picked; + }); + } + } + + String _formatDate(DateTime date) { + return '${date.day}/${date.month}/${date.year}'; + } + + String _formatTime(TimeOfDay time) { + final hour = time.hourOfPeriod == 0 ? 12 : time.hourOfPeriod; + final minute = time.minute.toString().padLeft(2, '0'); + final period = time.period == DayPeriod.am ? 'AM' : 'PM'; + return '$hour:$minute $period'; + } + + Widget _buildTextField({ + required TextEditingController controller, + required String label, + String? hint, + bool required = false, + TextInputType keyboardType = TextInputType.text, + int maxLines = 1, + String? Function(String?)? validator, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: TextFormField( + controller: controller, + keyboardType: keyboardType, + maxLines: maxLines, + decoration: InputDecoration( + labelText: required ? '$label *' : label, + hintText: hint, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: + validator ?? + (required ? (value) => _validateRequired(value, label) : null), + ), + ); + } + + Widget _buildDropdown({ + required String label, + required T value, + required List items, + required void Function(T?) onChanged, + required String Function(T) getDisplayText, + bool required = false, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: DropdownButtonFormField( + value: value, + decoration: InputDecoration( + labelText: required ? '$label *' : label, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + items: items.map((T item) { + return DropdownMenuItem( + value: item, + child: Text(getDisplayText(item)), + ); + }).toList(), + onChanged: onChanged, + ), + ); + } + + Widget _buildDateTimeSelector() { + return Column( + children: [ + // Due Date Selector + InkWell( + onTap: _selectDate, + borderRadius: BorderRadius.circular(12), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.surface, + ), + child: Row( + children: [ + Icon( + Icons.calendar_today, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Due Date', + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]), + ), + const SizedBox(height: 2), + Text( + _selectedDueDate != null + ? _formatDate(_selectedDueDate!) + : 'Select due date', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + const Spacer(), + if (_selectedDueDate != null) + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + setState(() { + _selectedDueDate = null; + _selectedTime = null; + }); + }, + ), + ], + ), + ), + ), + + // Time Selector (only show if date is selected) + if (_selectedDueDate != null) ...[ + const SizedBox(height: 16), + InkWell( + onTap: _selectTime, + borderRadius: BorderRadius.circular(12), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.surface, + ), + child: Row( + children: [ + Icon( + Icons.access_time, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Due Time', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.grey[600], + ), + ), + const SizedBox(height: 2), + Text( + _selectedTime != null + ? _formatTime(_selectedTime!) + : 'Select due time', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + ], + ), + ), + ), + ], + + const SizedBox(height: 16), + ], + ); + } + + Widget _buildSectionHeader(String title) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Text( + title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.primary, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Create Task'), + elevation: 0, + actions: [ + TextButton( + onPressed: _isLoading ? null : _createTask, + child: _isLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Save'), + ), + ], + ), + body: Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Basic Information Section + _buildSectionHeader('Basic Information'), + _buildTextField( + controller: _subjectController, + label: 'Subject', + required: true, + hint: 'Enter task subject', + ), + _buildTextField( + controller: _descriptionController, + label: 'Description', + hint: 'Enter task description (optional)', + maxLines: 3, + ), + + // Task Details Section + _buildSectionHeader('Task Details'), + _buildDropdown( + label: 'Status', + value: _selectedStatus, + items: TaskStatus.values, + onChanged: (TaskStatus? newValue) { + if (newValue != null) { + setState(() { + _selectedStatus = newValue; + }); + } + }, + getDisplayText: (status) => status.value, + required: true, + ), + _buildDropdown( + label: 'Priority', + value: _selectedPriority, + items: TaskPriority.values, + onChanged: (TaskPriority? newValue) { + if (newValue != null) { + setState(() { + _selectedPriority = newValue; + }); + } + }, + getDisplayText: (priority) => priority.value, + required: true, + ), + + // Due Date and Time Section + _buildSectionHeader('Due Date & Time'), + _buildDateTimeSelector(), + + // Associations Section + _buildSectionHeader('Associations'), + _buildTextField( + controller: _accountIdController, + label: 'Account ID', + hint: 'Enter associated account ID (optional)', + ), + _buildTextField( + controller: _contactIdController, + label: 'Contact ID', + hint: 'Enter associated contact ID (optional)', + ), + + const SizedBox(height: 32), + + // Create Button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isLoading ? null : _createTask, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: _isLoading + ? const Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ), + SizedBox(width: 12), + Text('Creating Task...'), + ], + ) + : const Text( + 'Create Task', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + + const SizedBox(height: 16), + + // Help text + Center( + child: Text( + 'Fields marked with * are required', + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]), + ), + ), + + const SizedBox(height: 32), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/task_detail_screen.dart b/lib/screens/task_detail_screen.dart new file mode 100644 index 0000000..cd3389b --- /dev/null +++ b/lib/screens/task_detail_screen.dart @@ -0,0 +1,716 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import '../models/api_models.dart'; +import '../services/tasks_service.dart'; + +class TaskDetailScreen extends StatefulWidget { + final String taskId; + + const TaskDetailScreen({super.key, required this.taskId}); + + @override + State createState() => _TaskDetailScreenState(); +} + +class _TaskDetailScreenState extends State { + final TasksService _tasksService = TasksService(); + + Task? _task; + bool _isLoading = true; + bool _hasError = false; + String? _errorMessage; + + @override + void initState() { + super.initState(); + _loadTaskDetails(); + } + + Future _loadTaskDetails() async { + setState(() { + _isLoading = true; + _hasError = false; + }); + + try { + final task = await _tasksService.getTaskById(widget.taskId); + + if (task != null && mounted) { + setState(() { + _task = task; + _isLoading = false; + }); + } else if (mounted) { + setState(() { + _hasError = true; + _errorMessage = 'Task not found'; + _isLoading = false; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _hasError = true; + _errorMessage = e.toString(); + _isLoading = false; + }); + } + } + } + + Future _copyToClipboard(String text, String label) async { + await Clipboard.setData(ClipboardData(text: text)); + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('$label copied to clipboard'))); + } + } + + Color _getPriorityColor(TaskPriority priority) { + switch (priority) { + case TaskPriority.low: + return Colors.green; + case TaskPriority.normal: + return Colors.orange; + case TaskPriority.high: + return Colors.red; + } + } + + Color _getStatusColor(TaskStatus status) { + switch (status) { + case TaskStatus.notStarted: + return Colors.grey; + case TaskStatus.inProgress: + return Colors.blue; + case TaskStatus.completed: + return Colors.green; + case TaskStatus.cancelled: + return Colors.red; + } + } + + String _formatDateTime(DateTime dateTime) { + return '${dateTime.day}/${dateTime.month}/${dateTime.year} at ${dateTime.hour}:${dateTime.minute.toString().padLeft(2, '0')}'; + } + + Widget _buildInfoSection({ + required String title, + required List children, + IconData? icon, + }) { + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + if (icon != null) ...[ + Icon( + icon, + size: 20, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 8), + ], + Text( + title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + ), + const SizedBox(height: 12), + ...children, + ], + ), + ), + ); + } + + Widget _buildInfoRow({ + required String label, + required String value, + bool copyable = false, + Widget? trailing, + }) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 100, + child: Text( + label, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Colors.grey[600], + fontWeight: FontWeight.w500, + ), + ), + ), + Expanded( + child: GestureDetector( + onTap: copyable ? () => _copyToClipboard(value, label) : null, + child: Text( + value, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + decoration: copyable ? TextDecoration.underline : null, + ), + ), + ), + ), + if (trailing != null) trailing, + ], + ), + ); + } + + Widget _buildStatusPriorityChips() { + if (_task == null) return const SizedBox.shrink(); + + return Row( + children: [ + // Status Chip + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: _getStatusColor(_task!.status).withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: _getStatusColor(_task!.status).withValues(alpha: 0.3), + ), + ), + child: Text( + _task!.status.value, + style: TextStyle( + color: _getStatusColor(_task!.status), + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ), + const SizedBox(width: 12), + // Priority Chip + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: _getPriorityColor(_task!.priority).withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: _getPriorityColor(_task!.priority).withValues(alpha: 0.3), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.flag, + size: 14, + color: _getPriorityColor(_task!.priority), + ), + const SizedBox(width: 4), + Text( + _task!.priority.value, + style: TextStyle( + color: _getPriorityColor(_task!.priority), + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ); + } + + Future _markTaskComplete() async { + if (_task == null) return; + + try { + final updatedTask = await _tasksService.updateTask( + _task!.id, + status: TaskStatus.completed.value, + ); + + if (updatedTask != null && mounted) { + setState(() { + _task = updatedTask; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Task "${_task!.subject}" marked as complete'), + backgroundColor: Colors.green, + ), + ); + } else if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to update task'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error updating task: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + } + + void _showDeleteConfirmation() { + if (_task == null) return; + + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Delete Task'), + content: Text( + 'Are you sure you want to delete "${_task!.subject}"? This action cannot be undone.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + _deleteTask(); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Delete'), + ), + ], + ); + }, + ); + } + + Future _deleteTask() async { + if (_task == null) return; + + try { + final success = await _tasksService.deleteTask(_task!.id); + + if (success && mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Task "${_task!.subject}" deleted successfully'), + backgroundColor: Colors.green, + ), + ); + // Navigate back to the tasks list + Navigator.of( + context, + ).pop(true); // Return true to indicate task was deleted + } else if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to delete task'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error deleting task: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + } + + Widget _buildCommentItem(TaskComment comment) { + return Card( + margin: const EdgeInsets.only(bottom: 8), + child: Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + CircleAvatar( + radius: 16, + backgroundColor: Theme.of(context).colorScheme.primary, + child: Text( + comment.author?.name.isNotEmpty == true + ? comment.author!.name[0].toUpperCase() + : 'U', + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + comment.author?.name ?? 'Unknown User', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + Text( + _formatDateTime(comment.createdAt), + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.grey[600], + ), + ), + ], + ), + ), + if (comment.isPrivate) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, + vertical: 2, + ), + decoration: BoxDecoration( + color: Colors.orange[100], + borderRadius: BorderRadius.circular(4), + ), + child: Text( + 'Private', + style: TextStyle( + color: Colors.orange[800], + fontSize: 10, + fontWeight: FontWeight.w500, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Text(comment.body, style: Theme.of(context).textTheme.bodyMedium), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(_task?.subject ?? 'Task Details'), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + elevation: 0, + actions: [ + if (_task != null) ...[ + IconButton( + icon: const Icon(Icons.edit), + onPressed: () async { + final result = await Navigator.of( + context, + ).pushNamed('/task-edit', arguments: widget.taskId); + // If task was updated successfully, refresh the task details + if (result == true) { + _loadTaskDetails(); + } + }, + ), + PopupMenuButton( + onSelected: (value) { + switch (value) { + case 'complete': + _markTaskComplete(); + break; + case 'delete': + _showDeleteConfirmation(); + break; + } + }, + itemBuilder: (context) => [ + if (_task!.status != TaskStatus.completed) + const PopupMenuItem( + value: 'complete', + child: Row( + children: [ + Icon(Icons.check_circle, color: Colors.green), + SizedBox(width: 8), + Text('Mark as Complete'), + ], + ), + ), + const PopupMenuItem( + value: 'delete', + child: Row( + children: [ + Icon(Icons.delete, color: Colors.red), + SizedBox(width: 8), + Text('Delete Task'), + ], + ), + ), + ], + ), + ], + ], + ), + body: _buildBody(), + ); + } + + Widget _buildBody() { + if (_isLoading) { + return const Center(child: CircularProgressIndicator()); + } + + if (_hasError) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + _errorMessage ?? 'Something went wrong', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadTaskDetails, + child: const Text('Retry'), + ), + ], + ), + ); + } + + if (_task == null) { + return const Center(child: Text('Task not found')); + } + + return RefreshIndicator( + onRefresh: _loadTaskDetails, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + physics: const AlwaysScrollableScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Task Header with Status and Priority + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _task!.subject, + style: Theme.of(context).textTheme.headlineSmall + ?.copyWith(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 12), + _buildStatusPriorityChips(), + if (_task!.isOverdue) ...[ + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: Colors.red[100], + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.warning, + color: Colors.red, + size: 16, + ), + const SizedBox(width: 4), + Text( + 'Overdue', + style: TextStyle( + color: Colors.red[700], + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ], + ), + ), + ], + ], + ), + ), + ), + + // Description + if (_task!.description != null && _task!.description!.isNotEmpty) + _buildInfoSection( + title: 'Description', + icon: Icons.description, + children: [ + Text( + _task!.description!, + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ), + + // Task Details + _buildInfoSection( + title: 'Task Details', + icon: Icons.info_outline, + children: [ + if (_task!.dueDate != null) + _buildInfoRow( + label: 'Due Date', + value: _formatDateTime(_task!.dueDate!), + ), + _buildInfoRow( + label: 'Created', + value: _formatDateTime(_task!.createdAt), + ), + if (_task!.updatedAt != _task!.createdAt) + _buildInfoRow( + label: 'Updated', + value: _formatDateTime(_task!.updatedAt), + ), + ], + ), + + // Owner Information + if (_task!.owner != null || _task!.createdBy != null) + _buildInfoSection( + title: 'People', + icon: Icons.people_outline, + children: [ + if (_task!.owner != null) ...[ + _buildInfoRow( + label: 'Owner', + value: _task!.owner!.name, + copyable: true, + ), + _buildInfoRow( + label: 'Email', + value: _task!.owner!.email, + copyable: true, + ), + ], + if (_task!.createdBy != null && + _task!.createdBy!.id != _task!.owner?.id) ...[ + const SizedBox(height: 8), + _buildInfoRow( + label: 'Created By', + value: _task!.createdBy!.name, + copyable: true, + ), + ], + ], + ), + + // Related Records + if (_task!.account != null || + _task!.contact != null || + _task!.opportunity != null) + _buildInfoSection( + title: 'Related Records', + icon: Icons.link, + children: [ + if (_task!.account != null) ...[ + _buildInfoRow( + label: 'Account', + value: _task!.account!.name, + ), + if (_task!.account!.phone != null) + _buildInfoRow( + label: 'Phone', + value: _task!.account!.phone!, + copyable: true, + ), + if (_task!.account!.website != null) + _buildInfoRow( + label: 'Website', + value: _task!.account!.website!, + copyable: true, + ), + ], + if (_task!.contact != null) ...[ + if (_task!.account != null) const SizedBox(height: 8), + _buildInfoRow( + label: 'Contact', + value: _task!.contact!.fullName, + ), + if (_task!.contact!.email != null) + _buildInfoRow( + label: 'Email', + value: _task!.contact!.email!, + copyable: true, + ), + if (_task!.contact!.phone != null) + _buildInfoRow( + label: 'Phone', + value: _task!.contact!.phone!, + copyable: true, + ), + ], + if (_task!.opportunity != null) ...[ + if (_task!.account != null || _task!.contact != null) + const SizedBox(height: 8), + _buildInfoRow( + label: 'Opportunity', + value: _task!.opportunity!.name, + ), + _buildInfoRow( + label: 'Amount', + value: + '\$${_task!.opportunity!.amount.toStringAsFixed(2)}', + ), + _buildInfoRow( + label: 'Stage', + value: _task!.opportunity!.stage, + ), + ], + ], + ), + + // Comments Section + if (_task!.comments != null && _task!.comments!.isNotEmpty) + _buildInfoSection( + title: 'Comments (${_task!.comments!.length})', + icon: Icons.comment_outlined, + children: [ + Column( + children: _task!.comments! + .map((comment) => _buildCommentItem(comment)) + .toList(), + ), + ], + ), + + const SizedBox(height: 80), // Bottom padding for FAB + ], + ), + ), + ); + } +} diff --git a/lib/screens/task_edit_screen.dart b/lib/screens/task_edit_screen.dart new file mode 100644 index 0000000..65b9a2d --- /dev/null +++ b/lib/screens/task_edit_screen.dart @@ -0,0 +1,694 @@ +import 'package:flutter/material.dart'; +import '../services/tasks_service.dart'; +import '../models/api_models.dart'; + +class TaskEditScreen extends StatefulWidget { + final String taskId; + + const TaskEditScreen({super.key, required this.taskId}); + + @override + State createState() => _TaskEditScreenState(); +} + +class _TaskEditScreenState extends State { + final GlobalKey _formKey = GlobalKey(); + final TasksService _tasksService = TasksService(); + + // Form controllers + final TextEditingController _subjectController = TextEditingController(); + final TextEditingController _descriptionController = TextEditingController(); + final TextEditingController _accountIdController = TextEditingController(); + final TextEditingController _contactIdController = TextEditingController(); + + bool _isLoading = true; + bool _isSaving = false; + bool _hasError = false; + String? _errorMessage; + + Task? _originalTask; + TaskStatus _selectedStatus = TaskStatus.notStarted; + TaskPriority _selectedPriority = TaskPriority.normal; + DateTime? _selectedDueDate; + TimeOfDay? _selectedTime; + + @override + void initState() { + super.initState(); + _loadTaskDetails(); + } + + @override + void dispose() { + _subjectController.dispose(); + _descriptionController.dispose(); + _accountIdController.dispose(); + _contactIdController.dispose(); + super.dispose(); + } + + Future _loadTaskDetails() async { + setState(() { + _isLoading = true; + _hasError = false; + }); + + try { + final task = await _tasksService.getTaskById(widget.taskId); + + if (task != null && mounted) { + setState(() { + _originalTask = task; + _populateFormFields(task); + _isLoading = false; + }); + } else if (mounted) { + setState(() { + _hasError = true; + _errorMessage = 'Task not found'; + _isLoading = false; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _hasError = true; + _errorMessage = e.toString(); + _isLoading = false; + }); + } + } + } + + void _populateFormFields(Task task) { + _subjectController.text = task.subject; + _descriptionController.text = task.description ?? ''; + _accountIdController.text = task.accountId ?? ''; + _contactIdController.text = task.contactId ?? ''; + + _selectedStatus = task.status; + _selectedPriority = task.priority; + + if (task.dueDate != null) { + _selectedDueDate = DateTime( + task.dueDate!.year, + task.dueDate!.month, + task.dueDate!.day, + ); + _selectedTime = TimeOfDay( + hour: task.dueDate!.hour, + minute: task.dueDate!.minute, + ); + } + } + + Future _updateTask() async { + if (!_formKey.currentState!.validate()) { + return; + } + + setState(() { + _isSaving = true; + }); + + try { + DateTime? dueDateTime; + if (_selectedDueDate != null) { + // Combine date and time + final time = _selectedTime ?? const TimeOfDay(hour: 9, minute: 0); + dueDateTime = DateTime( + _selectedDueDate!.year, + _selectedDueDate!.month, + _selectedDueDate!.day, + time.hour, + time.minute, + ); + } + + final updatedTask = await _tasksService.updateTask( + widget.taskId, + subject: _subjectController.text.trim() != _originalTask?.subject + ? _subjectController.text.trim() + : null, + description: + _descriptionController.text.trim() != + (_originalTask?.description ?? '') + ? (_descriptionController.text.trim().isEmpty + ? null + : _descriptionController.text.trim()) + : null, + status: _selectedStatus != _originalTask?.status + ? _selectedStatus.value + : null, + priority: _selectedPriority != _originalTask?.priority + ? _selectedPriority.value + : null, + dueDate: dueDateTime != _originalTask?.dueDate ? dueDateTime : null, + accountId: + _accountIdController.text.trim() != (_originalTask?.accountId ?? '') + ? (_accountIdController.text.trim().isEmpty + ? null + : _accountIdController.text.trim()) + : null, + contactId: + _contactIdController.text.trim() != (_originalTask?.contactId ?? '') + ? (_contactIdController.text.trim().isEmpty + ? null + : _contactIdController.text.trim()) + : null, + ); + + if (updatedTask != null && mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Task "${updatedTask.subject}" updated successfully'), + backgroundColor: Colors.green, + ), + ); + Navigator.of(context).pop(true); // Return true to indicate success + } else if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Failed to update task'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error updating task: $e'), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isSaving = false; + }); + } + } + } + + bool _hasChanges() { + if (_originalTask == null) return false; + + return _subjectController.text.trim() != _originalTask!.subject || + _descriptionController.text.trim() != + (_originalTask!.description ?? '') || + _selectedStatus != _originalTask!.status || + _selectedPriority != _originalTask!.priority || + _getDueDateTime() != _originalTask!.dueDate || + _accountIdController.text.trim() != (_originalTask!.accountId ?? '') || + _contactIdController.text.trim() != (_originalTask!.contactId ?? ''); + } + + DateTime? _getDueDateTime() { + if (_selectedDueDate == null) return null; + + final time = _selectedTime ?? const TimeOfDay(hour: 9, minute: 0); + return DateTime( + _selectedDueDate!.year, + _selectedDueDate!.month, + _selectedDueDate!.day, + time.hour, + time.minute, + ); + } + + Future _onWillPop() async { + if (!_hasChanges()) return true; + + final shouldDiscard = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Discard Changes?'), + content: const Text( + 'You have unsaved changes. Are you sure you want to discard them?', + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Discard'), + ), + ], + ), + ); + + return shouldDiscard ?? false; + } + + String? _validateRequired(String? value, String fieldName) { + if (value == null || value.trim().isEmpty) { + return '$fieldName is required'; + } + return null; + } + + Future _selectDate() async { + final DateTime? picked = await showDatePicker( + context: context, + initialDate: + _selectedDueDate ?? DateTime.now().add(const Duration(days: 1)), + firstDate: DateTime.now(), + lastDate: DateTime.now().add(const Duration(days: 365)), + builder: (context, child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: Theme.of(context).colorScheme.copyWith( + primary: Theme.of(context).colorScheme.primary, + ), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + setState(() { + _selectedDueDate = picked; + }); + } + } + + Future _selectTime() async { + if (_selectedDueDate == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Please select a due date first')), + ); + return; + } + + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: _selectedTime ?? const TimeOfDay(hour: 9, minute: 0), + builder: (context, child) { + return Theme( + data: Theme.of(context).copyWith( + colorScheme: Theme.of(context).colorScheme.copyWith( + primary: Theme.of(context).colorScheme.primary, + ), + ), + child: child!, + ); + }, + ); + + if (picked != null) { + setState(() { + _selectedTime = picked; + }); + } + } + + String _formatDate(DateTime date) { + return '${date.day}/${date.month}/${date.year}'; + } + + String _formatTime(TimeOfDay time) { + final hour = time.hourOfPeriod == 0 ? 12 : time.hourOfPeriod; + final minute = time.minute.toString().padLeft(2, '0'); + final period = time.period == DayPeriod.am ? 'AM' : 'PM'; + return '$hour:$minute $period'; + } + + Widget _buildTextField({ + required TextEditingController controller, + required String label, + String? hint, + bool required = false, + TextInputType keyboardType = TextInputType.text, + int maxLines = 1, + String? Function(String?)? validator, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: TextFormField( + controller: controller, + keyboardType: keyboardType, + maxLines: maxLines, + decoration: InputDecoration( + labelText: required ? '$label *' : label, + hintText: hint, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + validator: + validator ?? + (required ? (value) => _validateRequired(value, label) : null), + ), + ); + } + + Widget _buildDropdown({ + required String label, + required T value, + required List items, + required void Function(T?) onChanged, + required String Function(T) getDisplayText, + bool required = false, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: DropdownButtonFormField( + value: value, + decoration: InputDecoration( + labelText: required ? '$label *' : label, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + filled: true, + fillColor: Theme.of(context).colorScheme.surface, + ), + items: items.map((T item) { + return DropdownMenuItem( + value: item, + child: Text(getDisplayText(item)), + ); + }).toList(), + onChanged: onChanged, + ), + ); + } + + Widget _buildDateTimeSelector() { + return Column( + children: [ + // Due Date Selector + InkWell( + onTap: _selectDate, + borderRadius: BorderRadius.circular(12), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.surface, + ), + child: Row( + children: [ + Icon( + Icons.calendar_today, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Due Date', + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]), + ), + const SizedBox(height: 2), + Text( + _selectedDueDate != null + ? _formatDate(_selectedDueDate!) + : 'Select due date', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + const Spacer(), + if (_selectedDueDate != null) + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + setState(() { + _selectedDueDate = null; + _selectedTime = null; + }); + }, + ), + ], + ), + ), + ), + + // Time Selector (only show if date is selected) + if (_selectedDueDate != null) ...[ + const SizedBox(height: 16), + InkWell( + onTap: _selectTime, + borderRadius: BorderRadius.circular(12), + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.surface, + ), + child: Row( + children: [ + Icon( + Icons.access_time, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Due Time', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Colors.grey[600], + ), + ), + const SizedBox(height: 2), + Text( + _selectedTime != null + ? _formatTime(_selectedTime!) + : 'Select due time', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + ], + ), + ), + ), + ], + + const SizedBox(height: 16), + ], + ); + } + + Widget _buildSectionHeader(String title) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Text( + title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: Theme.of(context).colorScheme.primary, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: !_hasChanges(), + onPopInvokedWithResult: (didPop, result) async { + if (!didPop) { + final navigator = Navigator.of(context); + final shouldPop = await _onWillPop(); + if (shouldPop && mounted) { + navigator.pop(); + } + } + }, + child: Scaffold( + appBar: AppBar( + title: const Text('Edit Task'), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + elevation: 0, + actions: [ + TextButton( + onPressed: (_isSaving || !_hasChanges()) ? null : _updateTask, + child: _isSaving + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : const Text('Save'), + ), + ], + ), + body: _buildBody(), + ), + ); + } + + Widget _buildBody() { + if (_isLoading) { + return const Center(child: CircularProgressIndicator()); + } + + if (_hasError) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + _errorMessage ?? 'Something went wrong', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadTaskDetails, + child: const Text('Retry'), + ), + ], + ), + ); + } + + if (_originalTask == null) { + return const Center(child: Text('Task not found')); + } + + return Form( + key: _formKey, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Basic Information Section + _buildSectionHeader('Basic Information'), + _buildTextField( + controller: _subjectController, + label: 'Subject', + required: true, + hint: 'Enter task subject', + ), + _buildTextField( + controller: _descriptionController, + label: 'Description', + hint: 'Enter task description (optional)', + maxLines: 3, + ), + + // Task Details Section + _buildSectionHeader('Task Details'), + _buildDropdown( + label: 'Status', + value: _selectedStatus, + items: TaskStatus.values, + onChanged: (TaskStatus? newValue) { + if (newValue != null) { + setState(() { + _selectedStatus = newValue; + }); + } + }, + getDisplayText: (status) => status.value, + required: true, + ), + _buildDropdown( + label: 'Priority', + value: _selectedPriority, + items: TaskPriority.values, + onChanged: (TaskPriority? newValue) { + if (newValue != null) { + setState(() { + _selectedPriority = newValue; + }); + } + }, + getDisplayText: (priority) => priority.value, + required: true, + ), + + // Due Date and Time Section + _buildSectionHeader('Due Date & Time'), + _buildDateTimeSelector(), + + // Associations Section + _buildSectionHeader('Associations'), + _buildTextField( + controller: _accountIdController, + label: 'Account ID', + hint: 'Enter associated account ID (optional)', + ), + _buildTextField( + controller: _contactIdController, + label: 'Contact ID', + hint: 'Enter associated contact ID (optional)', + ), + + const SizedBox(height: 32), + + // Update Button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: (_isSaving || !_hasChanges()) ? null : _updateTask, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: _isSaving + ? const Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ), + SizedBox(width: 12), + Text('Updating Task...'), + ], + ) + : Text( + _hasChanges() ? 'Update Task' : 'No Changes', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + + const SizedBox(height: 16), + + // Help text + Center( + child: Text( + 'Fields marked with * are required', + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.grey[600]), + ), + ), + + const SizedBox(height: 32), + ], + ), + ), + ); + } +} diff --git a/lib/screens/tasks_list_screen.dart b/lib/screens/tasks_list_screen.dart new file mode 100644 index 0000000..f1745da --- /dev/null +++ b/lib/screens/tasks_list_screen.dart @@ -0,0 +1,775 @@ +import 'package:flutter/material.dart'; +import '../models/api_models.dart'; +import '../services/tasks_service.dart'; + +class TasksListScreen extends StatefulWidget { + const TasksListScreen({super.key}); + + @override + State createState() => _TasksListScreenState(); +} + +class _TasksListScreenState extends State { + final TasksService _tasksService = TasksService(); + final ScrollController _scrollController = ScrollController(); + + List _tasks = []; + bool _isLoading = true; + bool _isLoadingMore = false; + bool _hasError = false; + String? _errorMessage; + int _currentPage = 0; + bool _hasMoreData = true; + final int _limit = 10; + + // Filter options + String? _selectedStatus; + String? _selectedPriority; + + @override + void initState() { + super.initState(); + _loadTasks(); + _scrollController.addListener(_onScroll); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _onScroll() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + if (!_isLoadingMore && _hasMoreData) { + _loadMoreTasks(); + } + } + } + + Future _loadTasks({bool isRefresh = false}) async { + if (isRefresh) { + setState(() { + _currentPage = 0; + _hasMoreData = true; + _isLoading = true; + _hasError = false; + }); + } + + try { + final response = await _tasksService.getTasks( + status: _selectedStatus, + priority: _selectedPriority, + limit: _limit, + offset: _currentPage * _limit, + ); + + if (response != null) { + setState(() { + if (isRefresh || _currentPage == 0) { + _tasks = response.tasks; + } else { + _tasks.addAll(response.tasks); + } + _hasMoreData = + response.pagination?.hasNext ?? (response.tasks.length == _limit); + _isLoading = false; + _hasError = false; + }); + } else { + setState(() { + _hasError = true; + _errorMessage = 'Failed to load tasks'; + _isLoading = false; + }); + } + } catch (e) { + setState(() { + _hasError = true; + _errorMessage = e.toString(); + _isLoading = false; + }); + } + } + + Future _loadMoreTasks() async { + if (_isLoadingMore || !_hasMoreData) return; + + setState(() { + _isLoadingMore = true; + }); + + _currentPage++; + + try { + final response = await _tasksService.getTasks( + status: _selectedStatus, + priority: _selectedPriority, + limit: _limit, + offset: _currentPage * _limit, + ); + + if (response != null) { + setState(() { + _tasks.addAll(response.tasks); + _hasMoreData = + response.pagination?.hasNext ?? (response.tasks.length == _limit); + _isLoadingMore = false; + }); + } else { + setState(() { + _isLoadingMore = false; + _currentPage--; + }); + } + } catch (e) { + setState(() { + _isLoadingMore = false; + _currentPage--; + }); + } + } + + Future _onRefresh() async { + await _loadTasks(isRefresh: true); + } + + void _showFilters() { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (context, setModalState) { + return SafeArea( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Filter Tasks', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + const Text('Status:'), + const SizedBox(height: 8), + Wrap( + spacing: 8, + children: [ + FilterChip( + label: const Text('All'), + selected: _selectedStatus == null, + onSelected: (selected) { + setModalState(() { + _selectedStatus = selected + ? null + : _selectedStatus; + }); + }, + ), + ...TaskStatus.values.map( + (status) => FilterChip( + label: Text(status.value), + selected: _selectedStatus == status.value, + onSelected: (selected) { + setModalState(() { + _selectedStatus = selected + ? status.value + : null; + }); + }, + ), + ), + ], + ), + const SizedBox(height: 16), + const Text('Priority:'), + const SizedBox(height: 8), + Wrap( + spacing: 8, + children: [ + FilterChip( + label: const Text('All'), + selected: _selectedPriority == null, + onSelected: (selected) { + setModalState(() { + _selectedPriority = selected + ? null + : _selectedPriority; + }); + }, + ), + ...TaskPriority.values.map( + (priority) => FilterChip( + label: Text(priority.value), + selected: _selectedPriority == priority.value, + onSelected: (selected) { + setModalState(() { + _selectedPriority = selected + ? priority.value + : null; + }); + }, + ), + ), + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + setModalState(() { + _selectedStatus = null; + _selectedPriority = null; + }); + }, + child: const Text('Clear'), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: () { + Navigator.pop(context); + setState(() {}); + _loadTasks(isRefresh: true); + }, + child: const Text('Apply'), + ), + ], + ), + ], + ), + ), + ); + }, + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Tasks'), + actions: [ + IconButton( + icon: Icon( + Icons.filter_list, + color: (_selectedStatus != null || _selectedPriority != null) + ? Theme.of(context).colorScheme.primary + : null, + ), + onPressed: _showFilters, + ), + ], + ), + body: RefreshIndicator(onRefresh: _onRefresh, child: _buildContent()), + floatingActionButton: FloatingActionButton( + heroTag: "tasks_fab", + onPressed: () async { + final result = await Navigator.of(context).pushNamed('/task-create'); + // If task was created successfully, refresh the tasks list + if (result == true) { + _loadTasks(isRefresh: true); + } + }, + child: const Icon(Icons.add), + ), + ); + } + + Widget _buildContent() { + if (_isLoading && _tasks.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: const [ + SizedBox(height: 200), + Center(child: CircularProgressIndicator()), + ], + ); + } + + if (_hasError && _tasks.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.3), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + _errorMessage ?? 'Something went wrong', + style: Theme.of(context).textTheme.titleMedium, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () => _loadTasks(isRefresh: true), + child: const Text('Retry'), + ), + ], + ), + ), + ], + ); + } + + if (_tasks.isEmpty) { + return ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + SizedBox(height: MediaQuery.of(context).size.height * 0.3), + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.task_outlined, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + 'No tasks found', + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 8), + Text( + 'Create your first task to get started', + style: Theme.of( + context, + ).textTheme.bodyMedium?.copyWith(color: Colors.grey[600]), + ), + ], + ), + ), + ], + ); + } + + return ListView.builder( + controller: _scrollController, + physics: const AlwaysScrollableScrollPhysics(), + itemCount: _tasks.length + (_isLoadingMore ? 1 : 0), + itemBuilder: (context, index) { + if (index == _tasks.length) { + return const Center( + child: Padding( + padding: EdgeInsets.all(16.0), + child: CircularProgressIndicator(), + ), + ); + } + + final task = _tasks[index]; + return _buildTaskCard(task); + }, + ); + } + + Widget _buildTaskCard(Task task) { + final bool isOverdue = task.isOverdue; + final Color priorityColor = _getPriorityColor(task.priority); + + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + decoration: BoxDecoration( + color: Colors.white, + border: Border( + left: BorderSide(color: priorityColor, width: 3), + bottom: BorderSide( + color: isOverdue ? Colors.red.shade200 : Colors.grey.shade200, + width: 1, + ), + ), + ), + child: ListTile( + contentPadding: const EdgeInsets.all(16), + title: Row( + children: [ + Expanded( + child: Text( + task.title, + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + decoration: task.status == TaskStatus.completed + ? TextDecoration.lineThrough + : null, + ), + ), + ), + if (isOverdue) + const Icon(Icons.warning, color: Colors.red, size: 20), + ], + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + Row( + children: [ + _buildStatusChip(task.status), + const SizedBox(width: 8), + _buildPriorityChip(task.priority), + ], + ), + if (task.dueDate != null) ...[ + const SizedBox(height: 8), + Row( + children: [ + Icon( + Icons.schedule, + size: 16, + color: isOverdue ? Colors.red : Colors.grey[600], + ), + const SizedBox(width: 4), + Text( + _formatDueDate(task.dueDate!), + style: TextStyle( + color: isOverdue ? Colors.red : Colors.grey[600], + fontSize: 13, + fontWeight: isOverdue + ? FontWeight.w500 + : FontWeight.normal, + ), + ), + ], + ), + ], + if (task.description != null && task.description!.isNotEmpty) ...[ + const SizedBox(height: 4), + Text( + task.description!, + style: TextStyle(color: Colors.grey[600], fontSize: 13), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + if (task.owner != null) ...[ + const SizedBox(height: 4), + Row( + children: [ + Icon(Icons.person_outline, size: 16, color: Colors.grey[600]), + const SizedBox(width: 4), + Text( + task.owner!.name, + style: TextStyle( + color: Colors.grey[500], + fontSize: 12, + fontStyle: FontStyle.italic, + ), + ), + ], + ), + ], + if (task.account != null) ...[ + const SizedBox(height: 2), + Row( + children: [ + Icon( + Icons.business_outlined, + size: 16, + color: Colors.grey[600], + ), + const SizedBox(width: 4), + Text( + task.account!.name, + style: TextStyle( + color: Colors.grey[500], + fontSize: 12, + fontStyle: FontStyle.italic, + ), + ), + ], + ), + ], + if (task.contact != null) ...[ + const SizedBox(height: 2), + Row( + children: [ + Icon( + Icons.contact_phone_outlined, + size: 16, + color: Colors.grey[600], + ), + const SizedBox(width: 4), + Text( + task.contact!.fullName, + style: TextStyle( + color: Colors.grey[500], + fontSize: 12, + fontStyle: FontStyle.italic, + ), + ), + ], + ), + ], + ], + ), + trailing: IconButton( + icon: const Icon(Icons.more_vert), + onPressed: () { + _showTaskOptions(context, task); + }, + ), + onTap: () async { + final result = await Navigator.of( + context, + ).pushNamed('/task-detail', arguments: task.id); + // If task was deleted or modified, refresh the tasks list + if (result == true) { + _loadTasks(isRefresh: true); + } + }, + ), + ); + } + + Widget _buildStatusChip(TaskStatus status) { + Color backgroundColor; + Color textColor; + + switch (status) { + case TaskStatus.notStarted: + backgroundColor = Colors.grey[200]!; + textColor = Colors.grey[700]!; + break; + case TaskStatus.inProgress: + backgroundColor = Colors.blue[100]!; + textColor = Colors.blue[700]!; + break; + case TaskStatus.completed: + backgroundColor = Colors.green[100]!; + textColor = Colors.green[700]!; + break; + case TaskStatus.cancelled: + backgroundColor = Colors.red[100]!; + textColor = Colors.red[700]!; + break; + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + status.value, + style: TextStyle( + color: textColor, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ); + } + + Widget _buildPriorityChip(TaskPriority priority) { + final Color color = _getPriorityColor(priority); + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: color.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: color.withValues(alpha: 0.3)), + ), + child: Text( + priority.value, + style: TextStyle( + color: color, + fontSize: 12, + fontWeight: FontWeight.w500, + ), + ), + ); + } + + Color _getPriorityColor(TaskPriority priority) { + switch (priority) { + case TaskPriority.low: + return Colors.green; + case TaskPriority.normal: + return Colors.orange; + case TaskPriority.high: + return Colors.red; + } + } + + String _formatDueDate(DateTime dueDate) { + final now = DateTime.now(); + final difference = dueDate.difference(now); + + if (difference.isNegative) { + final days = difference.inDays.abs(); + if (days == 0) { + return 'Overdue today'; + } else if (days == 1) { + return 'Overdue by 1 day'; + } else { + return 'Overdue by $days days'; + } + } else { + final days = difference.inDays; + if (days == 0) { + return 'Due today'; + } else if (days == 1) { + return 'Due tomorrow'; + } else if (days < 7) { + return 'Due in $days days'; + } else { + return 'Due ${dueDate.day}/${dueDate.month}/${dueDate.year}'; + } + } + } + + void _showTaskOptions(BuildContext context, Task task) { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.visibility), + title: const Text('View Details'), + onTap: () async { + Navigator.pop(context); + final result = await Navigator.of( + context, + ).pushNamed('/task-detail', arguments: task.id); + // If task was deleted or modified, refresh the tasks list + if (result == true) { + _loadTasks(isRefresh: true); + } + }, + ), + ListTile( + leading: const Icon(Icons.edit), + title: const Text('Edit Task'), + onTap: () async { + Navigator.pop(context); + final result = await Navigator.of( + context, + ).pushNamed('/task-edit', arguments: task.id); + // If task was updated successfully, refresh the tasks list + if (result == true) { + _loadTasks(isRefresh: true); + } + }, + ), + if (task.status != TaskStatus.completed) + ListTile( + leading: const Icon(Icons.check_circle, color: Colors.green), + title: const Text('Mark as Complete'), + onTap: () { + Navigator.pop(context); + _markTaskComplete(task); + }, + ), + ListTile( + leading: const Icon(Icons.delete, color: Colors.red), + title: const Text( + 'Delete Task', + style: TextStyle(color: Colors.red), + ), + onTap: () { + Navigator.pop(context); + _showDeleteConfirmation(context, task); + }, + ), + ], + ), + ); + }, + ); + } + + void _showDeleteConfirmation(BuildContext context, Task task) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Delete Task'), + content: Text( + 'Are you sure you want to delete "${task.subject}"? This action cannot be undone.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.pop(context); + _deleteTask(task); + }, + style: TextButton.styleFrom(foregroundColor: Colors.red), + child: const Text('Delete'), + ), + ], + ); + }, + ); + } + + Future _markTaskComplete(Task task) async { + final success = await _tasksService.updateTask( + task.id, + status: TaskStatus.completed.value, + ); + + if (success != null) { + setState(() { + final index = _tasks.indexWhere((t) => t.id == task.id); + if (index != -1) { + _tasks[index] = success; + } + }); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Task "${task.subject}" marked as complete')), + ); + } + } else { + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Failed to update task'))); + } + } + } + + Future _deleteTask(Task task) async { + final success = await _tasksService.deleteTask(task.id); + + if (success) { + setState(() { + _tasks.removeWhere((t) => t.id == task.id); + }); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Task "${task.subject}" deleted successfully'), + ), + ); + } + } else { + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Failed to delete task'))); + } + } + } +} diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart new file mode 100644 index 0000000..9e80e44 --- /dev/null +++ b/lib/services/api_service.dart @@ -0,0 +1,281 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:http/http.dart' as http; +import '../config/api_config.dart'; +import 'auth_service.dart'; + +class ApiResponse { + final bool success; + final T? data; + final String? message; + final int statusCode; + final Map? errors; + + ApiResponse({ + required this.success, + this.data, + this.message, + required this.statusCode, + this.errors, + }); + + factory ApiResponse.success(T data, int statusCode) { + return ApiResponse(success: true, data: data, statusCode: statusCode); + } + + factory ApiResponse.error( + String message, + int statusCode, [ + Map? errors, + ]) { + return ApiResponse( + success: false, + message: message, + statusCode: statusCode, + errors: errors, + ); + } +} + +class ApiService { + static final ApiService _instance = ApiService._internal(); + factory ApiService() => _instance; + ApiService._internal(); + + final http.Client _client = http.Client(); + final AuthService _authService = AuthService(); + + Future> _getHeaders({bool requiresAuth = true}) async { + Map headers = Map.from(ApiConfig.defaultHeaders); + + if (requiresAuth) { + final token = await _authService.getJwtToken(); + if (token != null) { + headers['Authorization'] = 'Bearer $token'; + } + + // Add selected organization ID to headers for API calls + final selectedOrg = _authService.selectedOrganization; + if (selectedOrg != null) { + headers['X-Organization-ID'] = selectedOrg.id; + } + } + + return headers; + } + + Future> _handleResponse( + http.Response response, + T Function(Map) fromJson, + ) async { + try { + final Map body = json.decode(response.body); + + if (response.statusCode >= 200 && response.statusCode < 300) { + return ApiResponse.success(fromJson(body), response.statusCode); + } else { + // Handle unauthorized access - logout user + if (response.statusCode == 401) { + await _authService.logout(); + } + + return ApiResponse.error( + body['message'] ?? 'Request failed', + response.statusCode, + body['errors'], + ); + } + } catch (e) { + return ApiResponse.error( + 'Failed to parse response: $e', + response.statusCode, + ); + } + } + + Future>> _handleMapResponse( + http.Response response, + ) async { + return _handleResponse>(response, (json) => json); + } + + Future>>> _handleListResponse( + http.Response response, + ) async { + try { + final dynamic body = json.decode(response.body); + + if (response.statusCode >= 200 && response.statusCode < 300) { + if (body is Map && body.containsKey('data')) { + final List data = body['data'] as List; + final List> result = data + .cast>(); + return ApiResponse.success(result, response.statusCode); + } else if (body is List) { + final List> result = body + .cast>(); + return ApiResponse.success(result, response.statusCode); + } + } + + final Map errorBody = body is Map + ? body + : {}; + return ApiResponse.error( + errorBody['message'] ?? 'Request failed', + response.statusCode, + errorBody['errors'], + ); + } catch (e) { + return ApiResponse.error( + 'Failed to parse response: $e', + response.statusCode, + ); + } + } + + // GET request + Future>> get( + String endpoint, { + Map? queryParams, + bool requiresAuth = true, + }) async { + try { + Uri uri = Uri.parse(endpoint); + if (queryParams != null && queryParams.isNotEmpty) { + uri = uri.replace(queryParameters: queryParams); + } + + final headers = await _getHeaders(requiresAuth: requiresAuth); + final response = await _client + .get(uri, headers: headers) + .timeout(ApiConfig.receiveTimeout); + + return _handleMapResponse(response); + } on SocketException { + return ApiResponse.error('No internet connection', 0); + } on HttpException { + return ApiResponse.error('HTTP error occurred', 0); + } catch (e) { + return ApiResponse.error('Request failed: $e', 0); + } + } + + // GET request for lists + Future>>> getList( + String endpoint, { + Map? queryParams, + bool requiresAuth = true, + }) async { + try { + Uri uri = Uri.parse(endpoint); + if (queryParams != null && queryParams.isNotEmpty) { + uri = uri.replace(queryParameters: queryParams); + } + + final headers = await _getHeaders(requiresAuth: requiresAuth); + final response = await _client + .get(uri, headers: headers) + .timeout(ApiConfig.receiveTimeout); + + return _handleListResponse(response); + } on SocketException { + return ApiResponse.error('No internet connection', 0); + } on HttpException { + return ApiResponse.error('HTTP error occurred', 0); + } catch (e) { + return ApiResponse.error('Request failed: $e', 0); + } + } + + // POST request + Future>> post( + String endpoint, + Map data, { + bool requiresAuth = true, + }) async { + try { + final headers = await _getHeaders(requiresAuth: requiresAuth); + final response = await _client + .post(Uri.parse(endpoint), headers: headers, body: json.encode(data)) + .timeout(ApiConfig.sendTimeout); + + return _handleMapResponse(response); + } on SocketException { + return ApiResponse.error('No internet connection', 0); + } on HttpException { + return ApiResponse.error('HTTP error occurred', 0); + } catch (e) { + return ApiResponse.error('Request failed: $e', 0); + } + } + + // PUT request + Future>> put( + String endpoint, + Map data, { + bool requiresAuth = true, + }) async { + try { + final headers = await _getHeaders(requiresAuth: requiresAuth); + final response = await _client + .put(Uri.parse(endpoint), headers: headers, body: json.encode(data)) + .timeout(ApiConfig.sendTimeout); + + return _handleMapResponse(response); + } on SocketException { + return ApiResponse.error('No internet connection', 0); + } on HttpException { + return ApiResponse.error('HTTP error occurred', 0); + } catch (e) { + return ApiResponse.error('Request failed: $e', 0); + } + } + + // DELETE request + Future>> delete( + String endpoint, { + bool requiresAuth = true, + }) async { + try { + final headers = await _getHeaders(requiresAuth: requiresAuth); + final response = await _client + .delete(Uri.parse(endpoint), headers: headers) + .timeout(ApiConfig.receiveTimeout); + + return _handleMapResponse(response); + } on SocketException { + return ApiResponse.error('No internet connection', 0); + } on HttpException { + return ApiResponse.error('HTTP error occurred', 0); + } catch (e) { + return ApiResponse.error('Request failed: $e', 0); + } + } + + // PATCH request + Future>> patch( + String endpoint, + Map data, { + bool requiresAuth = true, + }) async { + try { + final headers = await _getHeaders(requiresAuth: requiresAuth); + final response = await _client + .patch(Uri.parse(endpoint), headers: headers, body: json.encode(data)) + .timeout(ApiConfig.sendTimeout); + + return _handleMapResponse(response); + } on SocketException { + return ApiResponse.error('No internet connection', 0); + } on HttpException { + return ApiResponse.error('HTTP error occurred', 0); + } catch (e) { + return ApiResponse.error('Request failed: $e', 0); + } + } + + void dispose() { + _client.close(); + } +} diff --git a/lib/services/auth_service.dart b/lib/services/auth_service.dart new file mode 100644 index 0000000..d4f6d21 --- /dev/null +++ b/lib/services/auth_service.dart @@ -0,0 +1,457 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:google_sign_in/google_sign_in.dart'; +import '../config/api_config.dart'; +import 'api_service.dart'; + +class OrganizationsPagination { + final int page; + final int limit; + final int total; + final int totalPages; + final bool hasNext; + final bool hasPrev; + + OrganizationsPagination({ + required this.page, + required this.limit, + required this.total, + required this.totalPages, + required this.hasNext, + required this.hasPrev, + }); + + factory OrganizationsPagination.fromJson(Map json) { + return OrganizationsPagination( + page: json['page'] ?? 1, + limit: json['limit'] ?? 10, + total: json['total'] ?? 0, + totalPages: json['totalPages'] ?? 1, + hasNext: json['hasNext'] ?? false, + hasPrev: json['hasPrev'] ?? false, + ); + } +} + +class Organization { + final String id; + final String name; + final String? domain; + final String? logo; + final String? website; + final String? industry; + final String? description; + final bool isActive; + final DateTime? createdAt; + final DateTime? updatedAt; + final String? userRole; + final DateTime? joinedAt; + + Organization({ + required this.id, + required this.name, + this.domain, + this.logo, + this.website, + this.industry, + this.description, + this.isActive = true, + this.createdAt, + this.updatedAt, + this.userRole, + this.joinedAt, + }); + + // Backward compatibility getter for existing code + String get role => userRole ?? 'USER'; + + factory Organization.fromJson(Map json) { + return Organization( + id: json['id'] ?? '', + name: json['name'] ?? '', + domain: json['domain'], + logo: json['logo'], + website: json['website'], + industry: json['industry'], + description: json['description'], + isActive: json['isActive'] ?? true, + createdAt: json['createdAt'] != null + ? DateTime.tryParse(json['createdAt']) + : null, + updatedAt: json['updatedAt'] != null + ? DateTime.tryParse(json['updatedAt']) + : null, + userRole: json['userRole'] ?? json['role'], + joinedAt: json['joinedAt'] != null + ? DateTime.tryParse(json['joinedAt']) + : null, + ); + } + + Map toJson() { + return { + 'id': id, + 'name': name, + 'domain': domain, + 'logo': logo, + 'website': website, + 'industry': industry, + 'description': description, + 'isActive': isActive, + 'createdAt': createdAt?.toIso8601String(), + 'updatedAt': updatedAt?.toIso8601String(), + 'userRole': userRole ?? 'USER', + 'joinedAt': joinedAt?.toIso8601String(), + }; + } +} + +class User { + final String id; + final String email; + final String name; + final String? profileImage; + + User({ + required this.id, + required this.email, + required this.name, + this.profileImage, + }); + + factory User.fromJson(Map json) { + return User( + id: json['id'] ?? '', + email: json['email'] ?? '', + name: json['name'] ?? '', + profileImage: json['profileImage'], + ); + } + + Map toJson() { + return { + 'id': id, + 'email': email, + 'name': name, + 'profileImage': profileImage, + }; + } +} + +class AuthService { + static final AuthService _instance = AuthService._internal(); + factory AuthService() => _instance; + AuthService._internal(); + + // Initialize GoogleSignIn instance (singleton in v7.1.1) + final GoogleSignIn _googleSignIn = GoogleSignIn.instance; + + static const String _jwtTokenKey = 'jwt_token'; + static const String _userKey = 'user_data'; + static const String _organizationsKey = 'organizations'; + static const String _selectedOrgKey = 'selected_organization'; + + User? _currentUser; + String? _jwtToken; + List? _organizations; + Organization? _selectedOrganization; + OrganizationsPagination? _organizationsPagination; + + // Getters + User? get currentUser => _currentUser; + bool get isLoggedIn => _currentUser != null && _jwtToken != null; + String? get jwtToken => _jwtToken; + List? get organizations => _organizations; + Organization? get selectedOrganization => _selectedOrganization; + bool get hasSelectedOrganization => _selectedOrganization != null; + OrganizationsPagination? get organizationsPagination => + _organizationsPagination; + + // Initialize service - call this in main.dart + Future initialize() async { + try { + // Initialize Google Sign-In (required in v7.1.1) + await _googleSignIn.initialize(); + debugPrint('Google Sign-In initialized successfully'); + } catch (e) { + debugPrint('Google Sign-In initialization failed: $e'); + } + + await _loadDataFromStorage(); + } + + // Google Sign In + Future signInWithGoogle() async { + try { + debugPrint('Google Sign-In: Initiating authentication process...'); + + // Check if platform supports authenticate method + if (!_googleSignIn.supportsAuthenticate()) { + debugPrint( + 'Google Sign-In: Platform does not support authenticate method', + ); + return false; + } + + // Authenticate with Google (new method in v7.1.1) + final googleUser = await _googleSignIn.authenticate(); + + debugPrint('Google Sign-In: Authentication successful'); + debugPrint('User authenticated: ${googleUser.email}'); + + // Get authentication token from Google + final authentication = googleUser.authentication; + final idToken = authentication.idToken; + + if (idToken == null) { + debugPrint('Google Sign-In: Failed to get ID token'); + return false; + } + + debugPrint('Google Sign-In: Got ID token, sending to backend...'); + + // Send Google token to backend + final apiService = ApiService(); + final response = await apiService.post(ApiConfig.googleLogin, { + 'idToken': idToken, + }, requiresAuth: false); + + if (!response.success || response.data == null) { + debugPrint( + 'Google Sign-In: Backend authentication failed: ${response.message}', + ); + return false; + } + + await _handleAuthResponse(response.data!); + + // Log user info after successful authentication + if (_currentUser != null) { + debugPrint('User ID: ${_currentUser!.id}'); + debugPrint('User Email: ${_currentUser!.email}'); + debugPrint('User Name: ${_currentUser!.name}'); + debugPrint('User Profile Image: ${_currentUser!.profileImage}'); + debugPrint( + 'Organizations: ${_organizations?.map((org) => '${org.name} (${org.role})').join(', ')}', + ); + } + + return true; + } catch (e) { + debugPrint('Google Sign In Error: $e'); + return false; + } + } + + // Handle authentication response from backend + Future _handleAuthResponse(Map data) async { + _jwtToken = data['JWTtoken']; + + if (data['user'] != null) { + _currentUser = User.fromJson(data['user']); + } + + if (data['organizations'] != null) { + _organizations = (data['organizations'] as List) + .map((org) => Organization.fromJson(org)) + .toList(); + } + + // Clear any previously selected organization on fresh login + // User must select a company again + _selectedOrganization = null; + await _clearSelectedOrganization(); + + await _saveDataToStorage(); + } + + // Select organization for API calls + Future selectOrganization(Organization organization) async { + _selectedOrganization = organization; + await _saveSelectedOrganization(); + debugPrint( + 'Selected organization: ${organization.name} (${organization.role})', + ); + } + + // Fetch organizations from API with pagination support + Future fetchOrganizations({ + int page = 1, + int limit = 10, + bool append = false, + }) async { + try { + debugPrint( + 'Fetching organizations from API (page: $page, limit: $limit)...', + ); + + final apiService = ApiService(); + final queryParams = {'page': page.toString(), 'limit': limit.toString()}; + + final response = await apiService.get( + ApiConfig.organizations, + queryParams: queryParams, + requiresAuth: true, + ); + + if (response.success && response.data != null) { + final data = response.data!; + if (data['success'] == true && data['organizations'] != null) { + final organizationsData = data['organizations'] as List; + final newOrganizations = organizationsData + .map((org) => Organization.fromJson(org)) + .toList(); + + // Handle pagination info + if (data['pagination'] != null) { + _organizationsPagination = OrganizationsPagination.fromJson( + data['pagination'], + ); + } + + // Append or replace organizations + if (append && _organizations != null) { + _organizations!.addAll(newOrganizations); + } else { + _organizations = newOrganizations; + } + + // Save to storage for offline access + await _saveDataToStorage(); + + debugPrint( + 'Fetched ${newOrganizations.length} organizations (total: ${_organizations!.length})', + ); + return true; + } + } + + debugPrint('Failed to fetch organizations: ${response.message}'); + return false; + } catch (e) { + debugPrint('Error fetching organizations: $e'); + return false; + } + } + + // Refresh organizations (fetch and update) + Future refreshOrganizations() async { + return await fetchOrganizations(); + } + + // Load more organizations (for pagination) + Future loadMoreOrganizations() async { + if (_organizationsPagination?.hasNext == true) { + final nextPage = (_organizationsPagination?.page ?? 0) + 1; + return await fetchOrganizations(page: nextPage, append: true); + } + return false; + } + + // Get JWT token for API calls + Future getJwtToken() async { + return _jwtToken; + } + + // Logout + Future logout() async { + try { + // Notify backend about logout + if (_jwtToken != null) { + final apiService = ApiService(); + await apiService.post(ApiConfig.logout, {}, requiresAuth: true); + } + } catch (e) { + debugPrint('Logout error: $e'); + } finally { + // Clear all local authentication data + await _clearDataFromStorage(); + + _currentUser = null; + _jwtToken = null; + _organizations = null; + _selectedOrganization = null; + _organizationsPagination = null; + + debugPrint('Logout: All authentication data cleared'); + } + } + + // Storage methods + Future _saveDataToStorage() async { + final prefs = await SharedPreferences.getInstance(); + + if (_jwtToken != null) { + await prefs.setString(_jwtTokenKey, _jwtToken!); + } + + if (_currentUser != null) { + await prefs.setString(_userKey, json.encode(_currentUser!.toJson())); + } + + if (_organizations != null) { + final orgsJson = _organizations!.map((org) => org.toJson()).toList(); + await prefs.setString(_organizationsKey, json.encode(orgsJson)); + } + } + + Future _saveSelectedOrganization() async { + if (_selectedOrganization != null) { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString( + _selectedOrgKey, + json.encode(_selectedOrganization!.toJson()), + ); + } + } + + Future _clearSelectedOrganization() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_selectedOrgKey); + } + + Future _loadDataFromStorage() async { + final prefs = await SharedPreferences.getInstance(); + + _jwtToken = prefs.getString(_jwtTokenKey); + + final userString = prefs.getString(_userKey); + if (userString != null) { + final userData = json.decode(userString); + _currentUser = User.fromJson(userData); + } + + final orgsString = prefs.getString(_organizationsKey); + if (orgsString != null) { + final orgsData = json.decode(orgsString) as List; + _organizations = orgsData + .map((org) => Organization.fromJson(org)) + .toList(); + } + + final selectedOrgString = prefs.getString(_selectedOrgKey); + if (selectedOrgString != null) { + final selectedOrgData = json.decode(selectedOrgString); + _selectedOrganization = Organization.fromJson(selectedOrgData); + } + } + + Future _clearDataFromStorage() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_jwtTokenKey); + await prefs.remove(_userKey); + await prefs.remove(_organizationsKey); + await prefs.remove(_selectedOrgKey); + } + + // Development helper method to clear all stored auth data + Future clearAllAuthData() async { + await _clearDataFromStorage(); + _currentUser = null; + _jwtToken = null; + _organizations = null; + _selectedOrganization = null; + debugPrint('All authentication data cleared'); + } +} diff --git a/lib/services/contacts_service.dart b/lib/services/contacts_service.dart new file mode 100644 index 0000000..87527f5 --- /dev/null +++ b/lib/services/contacts_service.dart @@ -0,0 +1,169 @@ +import '../config/api_config.dart'; +import '../models/api_models.dart'; +import 'api_service.dart'; +import 'auth_service.dart'; + +class ContactsService { + final ApiService _apiService = ApiService(); + final AuthService _authService = AuthService(); + + Future getContacts({ + int page = 1, + int limit = 20, + String? search, + }) async { + try { + if (!_authService.isLoggedIn) { + throw Exception('User not authenticated'); + } + + final Map queryParams = { + 'page': page.toString(), + 'limit': limit.toString(), + }; + + if (search != null && search.isNotEmpty) { + queryParams['search'] = search; + } + + final response = await _apiService.get( + ApiConfig.contacts, + queryParams: queryParams, + ); + + if (response.success && response.data != null) { + return ContactsResponse.fromJson(response.data!); + } else { + throw Exception(response.message ?? 'Failed to fetch contacts'); + } + } catch (e) { + // Error fetching contacts: $e + return null; + } + } + + Future getContactById(String contactId) async { + try { + if (!_authService.isLoggedIn) { + throw Exception('User not authenticated'); + } + + final url = ApiConfig.replacePathParam( + ApiConfig.contactById, + 'id', + contactId, + ); + + final response = await _apiService.get(url); + + if (response.success && response.data != null) { + return Contact.fromJson(response.data!); + } else { + throw Exception(response.message ?? 'Failed to fetch contact'); + } + } catch (e) { + // Error fetching contact: $e + return null; + } + } + + Future searchContacts( + String query, { + int page = 1, + int limit = 20, + }) async { + try { + if (!_authService.isLoggedIn) { + throw Exception('User not authenticated'); + } + + final Map queryParams = { + 'q': query, + 'page': page.toString(), + 'limit': limit.toString(), + }; + + final response = await _apiService.get( + ApiConfig.contactSearch, + queryParams: queryParams, + ); + + if (response.success && response.data != null) { + return ContactsResponse.fromJson(response.data!); + } else { + throw Exception(response.message ?? 'Failed to search contacts'); + } + } catch (e) { + // Error searching contacts: $e + return null; + } + } + + Future createContact(Map contactData) async { + try { + if (!_authService.isLoggedIn) { + throw Exception('User not authenticated'); + } + + final response = await _apiService.post(ApiConfig.contacts, contactData); + + if (response.success && response.data != null) { + return Contact.fromJson(response.data!); + } else { + throw Exception(response.message ?? 'Failed to create contact'); + } + } catch (e) { + // Error creating contact: $e + return null; + } + } + + Future updateContact( + String contactId, + Map contactData, + ) async { + try { + if (!_authService.isLoggedIn) { + throw Exception('User not authenticated'); + } + + final url = ApiConfig.replacePathParam( + ApiConfig.contactById, + 'id', + contactId, + ); + + final response = await _apiService.put(url, contactData); + + if (response.success && response.data != null) { + return Contact.fromJson(response.data!); + } else { + throw Exception(response.message ?? 'Failed to update contact'); + } + } catch (e) { + // Error updating contact: $e + return null; + } + } + + Future deleteContact(String contactId) async { + try { + if (!_authService.isLoggedIn) { + throw Exception('User not authenticated'); + } + + final url = ApiConfig.replacePathParam( + ApiConfig.contactById, + 'id', + contactId, + ); + + final response = await _apiService.delete(url); + + return response.success; + } catch (e) { + // Error deleting contact: $e + return false; + } + } +} diff --git a/lib/services/crm_services.dart b/lib/services/crm_services.dart deleted file mode 100644 index 86284b9..0000000 --- a/lib/services/crm_services.dart +++ /dev/null @@ -1,1040 +0,0 @@ -// import 'package:bottle_crm/bloc/setting_bloc.dart'; -// import 'package:bottle_crm/model/document.dart'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:file_picker/file_picker.dart'; -import 'package:http/http.dart'; -import 'package:http/http.dart' as http; -import 'package:bottle_crm/ui/screens/http_excepion.dart'; -import 'package:bottle_crm/config/api_config.dart'; - -import 'network_services.dart'; - -class CrmService { - NetworkService networkService = NetworkService(); - String baseUrl = ApiConfig.getApiUrl(); - - // Method to set custom API URL - void setBaseUrl(String url) { - baseUrl = url.endsWith('/') ? url : '$url/'; - } - - // Header handling now centralized in NetworkService - // These methods are deprecated and will be removed - - Future userRegister(data) async { - try { - return await networkService.post(Uri.parse(baseUrl + 'auth/register/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } on HandshakeException { - throw HttpException("Server Issue"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future googleLogin(String idToken) async { - try { - print("=== GOOGLE LOGIN DEBUG ==="); - print("Base URL: $baseUrl"); - print("Full URL: ${baseUrl}auth/google/"); - print("ID Token length: ${idToken.length}"); - print("=========================="); - - Map headers = { - 'Content-Type': 'application/json', - }; - return await networkService.post(Uri.parse(baseUrl + 'auth/google/'), - headers: headers, - body: jsonEncode({'idToken': idToken})); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } on FormatException { - throw HttpException("server issue"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future validateSubdomain(data) async { - try { - return await networkService - .post(Uri.parse(baseUrl + 'auth/validate-subdomain/'), body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future forgotPassword(data) async { - try { - return await networkService - .post(Uri.parse(baseUrl + 'auth/forgot-password/'), body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future getUserProfile() async { - try { - return await networkService.get(Uri.parse(baseUrl + 'profile/')); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future changePassword(data) async { - try { - return await networkService.post( - Uri.parse(baseUrl + 'profile/change-password/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future getCompanies() async { - try { - return await networkService.get( - Uri.parse(baseUrl + 'auth/companies-list/')); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future getDashboardDetails() async { - try { - return await networkService.get(Uri.parse(baseUrl + 'dashboard/')); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - ///////////////////// ACCONUTS-SERVICES //////////////////////////// - - Future getAccounts({queryParams, offset}) async { - - var url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'accounts/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - url = Uri.parse(baseUrl + 'accounts/'); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + "?offset=$offset"); - } - } - print(url); - return await networkService.get(url); - } - - Future deleteAccount(id) async { - try { - - return await networkService.delete(Uri.parse(baseUrl + 'accounts/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future createAccount(data, File file) async { - try { - if (file.path == "") { - - return await networkService.post(Uri.parse(baseUrl + 'accounts/'), - body: data); - } else { - var uri = Uri.parse( - baseUrl + 'accounts/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ) - ..fields.addAll(Map.from(data)) - ..files.add( - await http.MultipartFile.fromPath('document_file', 'assets/images/sentry_logo.png')); - await networkService.addAuthHeadersToMultipartRequest(request); - var response = await request.send(); - return await http.Response.fromStream(response); - } - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editAccount(data, id) async { - try { - - return await networkService.put(Uri.parse(baseUrl + 'accounts/$id/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future getToEditAccount(id) async { - - return await networkService.get(Uri.parse(baseUrl + 'accounts/$id/'), - ); - } - - ///////////////////// CONTACTS-SERVICES /////////////////////////////// - - Future getContacts({queryParams, offset}) async { - - var url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'contacts/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - url = Uri.parse(baseUrl + 'contacts/'); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '?offset=$offset'); - } - } - print(url); - return await networkService.get(url); - } - - Future createContact(data, File file) async { - try { - if (file.path == "") { - - return await networkService.post(Uri.parse(baseUrl + 'contacts/'), - body: data); - } else { - var uri = Uri.parse( - baseUrl + 'contacts/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll(Map.from(data)); - request.files.add( - await http.MultipartFile.fromPath('document_file', file.path)); - var response = await request.send(); - return await http.Response.fromStream(response); - } - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editContact(data, id) async { - try { - - return await networkService.put(Uri.parse(baseUrl + 'contacts/$id/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future deleteContact(id) async { - try { - - return await networkService.delete(Uri.parse(baseUrl + 'contacts/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - ///////////////////// LEADS-SERVICES /////////////////////////////// - - Future getLeads({queryParams, offset}) async { - - var url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = Uri( - queryParameters: queryParams, - ).query; - url = Uri.parse(baseUrl + 'leads/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - url = Uri.parse(baseUrl + 'leads/'); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + "?offset=$offset"); - } - } - print(url); - return await networkService.get(url); - } - - Future getLeadToUpdate(leadId) async { - - return await networkService.get(Uri.parse(baseUrl + 'leads/$leadId/'), - ); - } - - Future createLead(data, File file) async { - try { - if (file.path == "") { - - return await networkService.post(Uri.parse(baseUrl + 'leads/'), - body: data); - } else { - - var uri = Uri.parse( - baseUrl + 'leads/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll(Map.from(data)); - request.files.add( - await http.MultipartFile.fromPath('document_file', file.path)); - var response = await request.send(); - return await http.Response.fromStream(response); - } - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editLead(data, id) async { - try { - - return await networkService.put(Uri.parse(baseUrl + 'leads/$id/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future deleteLead(id) async { - try { - - return await networkService.delete(Uri.parse(baseUrl + 'leads/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - ///////////////////// USERS-SERVICES /////////////////////////////// - - Future getUsers({Map? queryParams}) async { - - Uri url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'users/' + '?' + queryString); - } else { - url = Uri.parse(baseUrl + 'users/'); - } - return await networkService.get(url); - } - - Future deleteUser(id) async { - try { - - return await networkService.delete(Uri.parse(baseUrl + 'users/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future createUser(user, File file) async { - try { - if (file.path == "") { - - return await networkService.post(Uri.parse(baseUrl + 'users/'), - body: user); - } else { - - var uri = Uri.parse( - baseUrl + 'users/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll(Map.from(user)); - request.files.add( - await http.MultipartFile.fromPath('document_file', file.path)); - var response = await request.send(); - return await http.Response.fromStream(response); - } - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editUser(user, id) async { - try { - - return await networkService.put(Uri.parse(baseUrl + 'users/$id/'), - body: user); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - - ///////////////////// Events-SERVICES /////////////////////////////// - - Future getEvents({Map? queryParams}) async { - - Uri url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'events/' + '?' + queryString); - } else { - url = Uri.parse(baseUrl + 'events/'); - } - print(url); - return await networkService.get(url); - } - - Future deleteEvent(id) async { - try { - - return await networkService.delete(Uri.parse(baseUrl + 'events/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future createEvent(user) async { - try { - - return await networkService.post(Uri.parse(baseUrl + 'events/'), - body: user); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editEvent(user, id) async { - try { - - return await networkService.put(Uri.parse(baseUrl + 'events/$id/'), - body: user); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - ///////////////////// DOCUMENTS-SERVICES /////////////////////////////// - - Future getDocuments({queryParams}) async { - - String url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = Uri( - queryParameters: queryParams, - ).query; - url = baseUrl + 'documents/' + '?' + queryString; - } else { - url = baseUrl + 'documents/'; - } - return await networkService.get(url); - } - - getFileSizes(files) { - List _fileSizeList = []; - // files.forEach((Document file) async { - // http.Response r = await http.head(Uri.parse(file.documentFile)); - // if (r.headers['content-length'] != null) { - // String fileSize = r.headers['content-length'].toString(); - // _fileSizeList.add([file.id, fileSize]); - // } else { - // _fileSizeList.add([file.id, "0"]); - // } - // }); - // print(_fileSizeList); - return _fileSizeList; - } - - Future createDocument(document, PlatformFile file) async { - try { - - var uri = Uri.parse( - baseUrl + 'documents/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll({ - 'title': document['title'], - 'teams': document['teams'], - 'shared_to': document['shared_to'] - }); - request.files.add( - await http.MultipartFile.fromPath('document_file', file.path!)); - final response = await request.send(); - return await response.stream.bytesToString(); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editDocument(document, PlatformFile file, id) async { - - var uri = Uri.parse( - baseUrl + 'documents/$id/', - ); - var request = http.MultipartRequest( - 'PUT', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll({ - 'title': document['title'], - 'teams': document['teams'], - 'shared_to': document['shared_to'], - 'status': document['status'] - }); - request.files - .add(await http.MultipartFile.fromPath('document_file', file.path!)); - return await request.send(); - } - - Future deleteDocument(id) async { - try { - - return await networkService.delete(Uri.parse(baseUrl + 'documents/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - ///////////////////// TEAMS-SERVICES /////////////////////////////// - - Future getTeams({queryParams, offset}) async { - - Uri url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value.runtimeType != String); - queryParams.removeWhere((key, value) => value == "[]"); - queryParams.removeWhere((key, value) => value == ""); - queryParams.removeWhere((key, value) => value == null); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'teams/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - url = Uri.parse(baseUrl + 'teams/'); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '?offset=$offset'); - } - } - print(url); - return await networkService.get(url); - } - - Future createTeam(data) async { - try { - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - - return await networkService.post(Uri.parse(baseUrl + 'teams/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future deleteTeam(id) async { - - return await networkService.delete(Uri.parse(baseUrl + 'teams/$id/'), - ); - } - - Future editTeam( - data, - id, - ) async { - - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - return await networkService.put(Uri.parse(baseUrl + 'teams/$id/'), - body: data); - } - - ///////////////////// OPPORTUNITIES-SERVICES //////////////////////////// - - Future getOpportunities({queryParams, offset}) async { - - Uri url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'opportunities/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - url = Uri.parse(baseUrl + 'opportunities/'); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '?offset=$offset'); - } - } - print(url); - return await networkService.get(url); - } - - Future deletefromModule(moduleName, id) async { - try { - - return await networkService.delete( - Uri.parse(baseUrl + '$moduleName/$id/'), - ); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - // Future createOpportunity(opportunity, [PlatformFile file]) async { - // file = null; - // - // var uri = Uri.parse( - // baseUrl + 'opportunities/', - // ); - // var request = http.MultipartRequest( - // 'POST', - // uri, - // ) - // // Headers automatically added by NetworkService - // ..fields.addAll({ - // 'name': opportunity['name'], - // 'account': opportunity['account'], - // 'amount': opportunity['amount'], - // 'currency': opportunity['currency'], - // 'stage': opportunity['stage'], - // 'lead_source': opportunity['lead_source'], - // 'probability': opportunity['probability'], - // 'description': opportunity['description'], - // 'teams': opportunity['teams'], - // 'assigned_to': opportunity['assigned_to'], - // 'contacts': opportunity['contacts'], - // 'due_date': opportunity['due_date'], - // 'tags': opportunity['tags'], - // }); - // if (file != null) { - // request.files.add(await http.MultipartFile.fromPath( - // 'opportunity_attachment', file.path)); - // } - // final response = await request.send(); - // return await response.stream.bytesToString(); - // } - - Future createOpportunity(data, File file) async { - try { - if (file.path == "") { - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - - return await networkService.post(Uri.parse(baseUrl + 'opportunities/'), - body: data); - } else { - - var uri = Uri.parse( - baseUrl + 'opportunities/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll(Map.from(data)); - request.files.add( - await http.MultipartFile.fromPath('document_file', file.path)); - var response = await request.send(); - return await http.Response.fromStream(response); - } - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editOpportunity(data, id, [PlatformFile? file]) async { - try { - - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - return await networkService.put(Uri.parse(baseUrl + 'opportunities/$id/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - // Future editOpportunity(opportunity, id, [PlatformFile file]) async { - // - // var uri = Uri.parse( - // baseUrl + 'opportunities`/$id/', - // ); - - // var request = http.MultipartRequest( - // 'PUT', - // uri, - // ) - // // Headers automatically added by NetworkService - // ..fields.addAll({ - // 'name': opportunity['name'], - // 'account': opportunity['account'], - // 'amount': opportunity['amount'], - // 'currency': opportunity['currency'], - // 'stage': opportunity['stage'], - // 'lead_source': opportunity['lead_source'], - // 'probability': opportunity['probability'], - // 'description': opportunity['description'], - // 'teams': opportunity['teams'], - // 'assigned_to': opportunity['assigned_to'], - // 'contacts': opportunity['contacts'], - // 'tags': opportunity['tags'], - // }) - // // ..files.add(await http.MultipartFile.fromPath( - // // 'opportunity_attachment', file.path)) - // ; - // final response = await request.send(); - // return await response.stream.bytesToString(); - - ///////////////////// TASKS-SERVICES /////////////////////////////// - - Future getTasks({queryParams, offset}) async { - - Uri? url; - if (queryParams != null) { - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'tasks/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '?offset=$offset'); - } - url = Uri.parse(baseUrl + 'tasks/'); - } - print(url); - return await networkService.get(url); - } - - Future createTask(data) async { - try { - - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - return await networkService.post(Uri.parse(baseUrl + 'tasks/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editTask(data, id) async { - - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - return await networkService.put(Uri.parse(baseUrl + 'tasks/$id/'), - body: data); - } - - Future deleteTask(id) async { - - return await networkService.delete(Uri.parse(baseUrl + 'tasks/$id/'), - ); - } - - ///////////////////// SETTINGS-SERVICES /////////////////////////////// - - Future getApiSettings({queryParams, offset}) async { - - Uri? url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'api-settings/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '?offset=$offset'); - } - url = Uri.parse(baseUrl + 'api-settings/'); - } - print(url); - return await networkService.get(url); - } - - /// CONTACTS - Future getSettingsContacts({queryParams}) async { - - String url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = baseUrl + 'settings/contacts/' + '?' + queryString; - } else { - url = baseUrl + 'settings/contacts/'; - } - return await networkService.get(url); - } - - Future deleteSettingsContacts(id) async { - - return await networkService.delete( - Uri.parse(baseUrl + 'settings/contacts/$id/'), - ); - } - - /// BLOCKED DOMAINS - Future getBlockedDomains({queryParams}) async { - - String url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = baseUrl + 'settings/block-domains/' + '?' + queryString; - } else { - url = baseUrl + 'settings/block-domains/'; - } - return await networkService.get(url); - } - - Future deleteBlockedDomains(id) async { - - return await networkService.delete( - Uri.parse(baseUrl + 'settings/block-domains/$id/'), - ); - } - - /// BLOCKED EMAILS - Future getBlockedEmails({queryParams}) async { - - String url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = baseUrl + 'settings/block-emails/' + '?' + queryString; - } else { - url = baseUrl + 'settings/block-emails/'; - } - return await networkService.get(url); - } - - Future deleteBlockedEmails(id) async { - - return await networkService.delete( - Uri.parse(baseUrl + 'settings/block-emails/$id/'), - ); - } - - Future createSetting(data) async { - try { - - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - String _url; - // if (settingsBloc.currentSettingsTab == "Contacts") { - _url = '/settings/contacts'; - // } else if (settingsBloc.currentSettingsTab == "Blocked Domains") { - // _url = '/settings/block-domains'; - // } else { - // _url = '/settings/block-emails'; - // } - return await networkService.post(Uri.parse(baseUrl + '$_url/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editSetting(data, id) async { - - data.removeWhere((key, value) => value == "[]"); - data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - String _url; - // if (settingsBloc.currentSettingsTab == "Contacts") { - _url = '/settings/contacts'; - // } else if (settingsBloc.currentSettingsTab == "Blocked Domains") { - // _url = '/settings/block-domains'; - // } else { - // _url = '/settings/block-emails'; - // } - return await networkService.put(Uri.parse(baseUrl + '$_url/$id/'), - body: data); - } - - ///////////////////// CASES-SERVICES /////////////////////////////// - - Future getCases({queryParams, offset}) async { - - Uri url; - if (queryParams != null) { - queryParams.removeWhere((key, value) => value == ""); - queryParams.removeWhere((key, value) => value == null); - queryParams.removeWhere((key, value) => value == []); - - String queryString = - Uri(queryParameters: Map.from(queryParams)).query; - url = Uri.parse(baseUrl + 'cases/' + '?' + queryString); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '&offset=$offset'); - } - } else { - url = Uri.parse(baseUrl + 'cases/'); - if (offset != null && offset != "") { - url = Uri.parse(url.toString() + '?offset=$offset'); - } - } - print(url); - return await networkService.get(url); - } - - Future createCase(data, File file) async { - try { - if (file.path == "") { - // data.removeWhere((key, value) => value == "[]"); - // data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - - return await networkService.post(Uri.parse(baseUrl + 'cases/'), - body: data); - } else { - - var uri = Uri.parse( - baseUrl + 'leads/', - ); - var request = http.MultipartRequest( - 'POST', - uri, - ); - await networkService.addAuthHeadersToMultipartRequest(request); - request.fields.addAll(Map.from(data)); - request.files.add( - await http.MultipartFile.fromPath('document_file', file.path)); - var response = await request.send(); - return await http.Response.fromStream(response); - } - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } - - Future editCase(data, id, [PlatformFile? file]) async { - try { - - // data.removeWhere((key, value) => value == "[]"); - // data.removeWhere((key, value) => value == ""); - data.removeWhere((key, value) => value == null); - return await networkService.put(Uri.parse(baseUrl + 'cases/$id/'), - body: data); - } on SocketException { - throw HttpException("Network Error, check your internet"); - } catch (e) { - throw HttpException(e.toString()); - } - } -} diff --git a/lib/services/dashboard_service.dart b/lib/services/dashboard_service.dart new file mode 100644 index 0000000..d7a30dc --- /dev/null +++ b/lib/services/dashboard_service.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import '../models/api_models.dart'; +import '../config/api_config.dart'; +import 'api_service.dart'; + +class DashboardService { + static final DashboardService _instance = DashboardService._internal(); + factory DashboardService() => _instance; + DashboardService._internal(); + + DashboardMetrics? _dashboardMetrics; + + DashboardMetrics? get dashboardMetrics => _dashboardMetrics; + + Future loadDashboardData() async { + try { + final apiService = ApiService(); + final response = await apiService.get(ApiConfig.dashboard); + + if (response.success && response.data != null) { + _dashboardMetrics = DashboardMetrics.fromJson(response.data!); + debugPrint( + 'Dashboard data loaded: ${_dashboardMetrics!.totalContacts} contacts, ${_dashboardMetrics!.totalLeads} leads', + ); + debugPrint( + 'Opportunities: ${_dashboardMetrics!.totalOpportunities}, Revenue: \$${_dashboardMetrics!.opportunityRevenue}', + ); + return _dashboardMetrics; + } else { + debugPrint('Failed to load dashboard data: ${response.message}'); + return null; + } + } catch (e) { + debugPrint('Dashboard service error: $e'); + return null; + } + } + + void clearDashboardData() { + _dashboardMetrics = null; + } +} diff --git a/lib/services/leads_service.dart b/lib/services/leads_service.dart new file mode 100644 index 0000000..8dec095 --- /dev/null +++ b/lib/services/leads_service.dart @@ -0,0 +1,254 @@ +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../config/api_config.dart'; +import '../models/api_models.dart'; +import 'api_service.dart'; + +class LeadsService { + static final LeadsService _instance = LeadsService._internal(); + factory LeadsService() => _instance; + LeadsService._internal(); + + final ApiService _apiService = ApiService(); + + // Cache for leads metadata (if any) + List? _cachedStatuses; + List? _cachedSources; + List? _cachedRatings; + List? _cachedIndustries; + + // Initialize service - load cached metadata + Future initialize() async { + await _loadCachedMetadata(); + } + + // Load leads with pagination + Future getLeads({ + int page = 1, + int limit = 10, + String? status, + String? leadSource, + String? rating, + String? industry, + String? searchQuery, + bool? converted, + }) async { + try { + final queryParams = { + 'page': page.toString(), + 'limit': limit.toString(), + }; + + if (status != null && status.isNotEmpty) { + queryParams['status'] = status; + } + if (leadSource != null && leadSource.isNotEmpty) { + queryParams['leadSource'] = leadSource; + } + if (rating != null && rating.isNotEmpty) { + queryParams['rating'] = rating; + } + if (industry != null && industry.isNotEmpty) { + queryParams['industry'] = industry; + } + if (searchQuery != null && searchQuery.isNotEmpty) { + queryParams['search'] = searchQuery; + } + if (converted != null) { + queryParams['converted'] = converted.toString(); + } + + final queryString = queryParams.entries + .map((e) => '${e.key}=${Uri.encodeComponent(e.value)}') + .join('&'); + + final url = queryString.isNotEmpty + ? '${ApiConfig.leads}?$queryString' + : ApiConfig.leads; + + debugPrint('LeadsService: Fetching leads from $url'); + + final response = await _apiService.get(url); + + if (response.success && response.data != null) { + final leadsResponse = LeadsResponse.fromJson(response.data!); + debugPrint( + 'LeadsService: Successfully loaded ${leadsResponse.leads.length} leads', + ); + return leadsResponse; + } else { + debugPrint('LeadsService: Failed to load leads - ${response.message}'); + return null; + } + } catch (e) { + debugPrint('LeadsService: Error loading leads - $e'); + return null; + } + } + + // Get a single lead by ID + Future getLeadById(String id) async { + try { + final url = ApiConfig.leadById.replaceAll('{id}', id); + final response = await _apiService.get(url); + + if (response.success && response.data != null) { + return Lead.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('LeadsService: Error loading lead $id - $e'); + return null; + } + } + + // Search leads + Future searchLeads({ + required String query, + int page = 1, + int limit = 10, + }) async { + try { + final queryParams = { + 'q': query, + 'page': page.toString(), + 'limit': limit.toString(), + }; + + final queryString = queryParams.entries + .map((e) => '${e.key}=${Uri.encodeComponent(e.value)}') + .join('&'); + + final url = '${ApiConfig.leadSearch}?$queryString'; + final response = await _apiService.get(url); + + if (response.success && response.data != null) { + return LeadsResponse.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('LeadsService: Error searching leads - $e'); + return null; + } + } + + // Create a new lead + Future createLead(Map leadData) async { + try { + final response = await _apiService.post(ApiConfig.leads, leadData); + + if (response.success && response.data != null) { + return Lead.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('LeadsService: Error creating lead - $e'); + return null; + } + } + + // Update an existing lead + Future updateLead(String id, Map leadData) async { + try { + final url = ApiConfig.leadById.replaceAll('{id}', id); + final response = await _apiService.put(url, leadData); + + if (response.success && response.data != null) { + return Lead.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('LeadsService: Error updating lead - $e'); + return null; + } + } + + // Delete a lead + Future deleteLead(String id) async { + try { + final url = ApiConfig.leadById.replaceAll('{id}', id); + final response = await _apiService.delete(url); + return response.success; + } catch (e) { + debugPrint('LeadsService: Error deleting lead - $e'); + return false; + } + } + + // Convert lead to contact/account/opportunity + Future convertLead( + String id, + Map conversionData, + ) async { + try { + final url = ApiConfig.leadConvert.replaceAll('{id}', id); + final response = await _apiService.post(url, conversionData); + return response.success; + } catch (e) { + debugPrint('LeadsService: Error converting lead - $e'); + return false; + } + } + + // Load cached metadata from SharedPreferences + Future _loadCachedMetadata() async { + try { + final prefs = await SharedPreferences.getInstance(); + + final statusesJson = prefs.getString('leads_statuses'); + if (statusesJson != null) { + final statusesList = jsonDecode(statusesJson) as List; + _cachedStatuses = statusesList.cast(); + } + + final sourcesJson = prefs.getString('leads_sources'); + if (sourcesJson != null) { + final sourcesList = jsonDecode(sourcesJson) as List; + _cachedSources = sourcesList.cast(); + } + + final ratingsJson = prefs.getString('leads_ratings'); + if (ratingsJson != null) { + final ratingsList = jsonDecode(ratingsJson) as List; + _cachedRatings = ratingsList.cast(); + } + + final industriesJson = prefs.getString('leads_industries'); + if (industriesJson != null) { + final industriesList = jsonDecode(industriesJson) as List; + _cachedIndustries = industriesList.cast(); + } + + debugPrint('LeadsService: Loaded cached metadata'); + } catch (e) { + debugPrint('LeadsService: Error loading cached metadata - $e'); + } + } + + // Clear all cached data (call this on logout or organization change) + Future clearCache() async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('leads_statuses'); + await prefs.remove('leads_sources'); + await prefs.remove('leads_ratings'); + await prefs.remove('leads_industries'); + + _cachedStatuses = null; + _cachedSources = null; + _cachedRatings = null; + _cachedIndustries = null; + + debugPrint('LeadsService: Cleared all cached data'); + } catch (e) { + debugPrint('LeadsService: Error clearing cache - $e'); + } + } + + // Getters for cached metadata + List? get statuses => _cachedStatuses; + List? get sources => _cachedSources; + List? get ratings => _cachedRatings; + List? get industries => _cachedIndustries; +} diff --git a/lib/services/network_services.dart b/lib/services/network_services.dart deleted file mode 100644 index 8ce2841..0000000 --- a/lib/services/network_services.dart +++ /dev/null @@ -1,217 +0,0 @@ -import 'dart:io'; - -import 'package:http/http.dart' as http; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:bottle_crm/ui/screens/http_excepion.dart'; - -class NetworkService { - static NetworkService _instance = new NetworkService.internal(); - factory NetworkService() => _instance; - http.Response? response; - var client = http.Client(); - - NetworkService.internal(); - - // Centralized method to get headers with JWT token and organization - Future> _getAuthenticatedHeaders([Map? additionalHeaders]) async { - final SharedPreferences preferences = await SharedPreferences.getInstance(); - - Map headers = { - 'Content-Type': 'application/json', - }; - - // Add Bearer token if available - final String? authToken = preferences.getString('authToken'); - if (authToken != null) { - // Convert from "JWT " format to "Bearer " format - String bearerToken = authToken; - if (authToken.startsWith('JWT ')) { - bearerToken = authToken.replaceFirst('JWT ', 'Bearer '); - } else if (!authToken.startsWith('Bearer ')) { - bearerToken = 'Bearer $authToken'; - } - headers['Authorization'] = bearerToken; - } - - // Add organization header if available - final String? org = preferences.getString('org'); - if (org != null) { - headers['X-Organization-ID'] = org; - } - - // Merge with any additional headers provided - if (additionalHeaders != null) { - headers.addAll(additionalHeaders); - } - - return headers; - } - - // Helper method to add authenticated headers to MultipartRequest - Future addAuthHeadersToMultipartRequest(http.MultipartRequest request) async { - final headers = await _getAuthenticatedHeaders(); - request.headers.addAll(headers); - } - - // Helper method to print long strings in chunks - void _printLongString(String title, String content) { - const int chunkSize = 800; - print(title); - if (content.length <= chunkSize) { - print(content); - } else { - for (int i = 0; i < content.length; i += chunkSize) { - int endIndex = (i + chunkSize < content.length) ? i + chunkSize : content.length; - print("${content.substring(i, endIndex)}"); - } - } - } - - Future get(var url, {Map? headers}) async { - try { - // Get authenticated headers (merge with provided headers) - Map finalHeaders = await _getAuthenticatedHeaders(headers); - - // Log request details - print("=== GET REQUEST ==="); - print("URL: $url"); - print("Headers: $finalHeaders"); - print("=================="); - - return client.get(url, headers: finalHeaders).then((http.Response response) { - // Log response details - print("=== GET RESPONSE ==="); - print("Status Code: ${response.statusCode}"); - print("Response Headers: ${response.headers}"); - _printLongString("Response Body:", response.body); - print("==================="); - - return handleResponse(response); - }); - } on SocketException { - print("=======Socket Exception"); - throw HttpException("Network Error, check your internet"); - } catch (e) { - print("=======Exception: $e"); - throw HttpException("Something Went Wrong"); - } finally { - // client.close(); - } - } - - Future post(Uri url, - {Map? headers, body, encoding}) async { - try { - // Get authenticated headers (merge with provided headers) - Map finalHeaders = await _getAuthenticatedHeaders(headers); - - // Log request details - print("=== POST REQUEST ==="); - print("URL: $url"); - print("Headers: $finalHeaders"); - _printLongString("Body:", body?.toString() ?? "null"); - print("=================="); - - return client - .post(url, headers: finalHeaders, body: body, encoding: encoding) - .then((http.Response response) { - // Log response details - print("=== POST RESPONSE ==="); - print("Status Code: ${response.statusCode}"); - print("Response Headers: ${response.headers}"); - _printLongString("Response Body:", response.body); - print("===================="); - - return handleResponse(response); - }); - } on FormatException { - print("=========Format Exception"); - throw HttpException("Server issue"); - } on SocketException { - print("=======Socket Exception"); - throw HttpException("Network Error, check your internet"); - } catch (e) { - print("=======Exception: $e"); - throw HttpException("Something Went Wrong"); - } finally { - // client.close(); - } - } - - Future put(Uri url, - {Map? headers, body, encoding}) async { - try { - // Get authenticated headers (merge with provided headers) - Map finalHeaders = await _getAuthenticatedHeaders(headers); - - // Log request details - print("=== PUT REQUEST ==="); - print("URL: $url"); - print("Headers: $finalHeaders"); - _printLongString("Body:", body?.toString() ?? "null"); - print("=================="); - - return client - .put(url, headers: finalHeaders, body: body, encoding: encoding) - .then((http.Response response) { - // Log response details - print("=== PUT RESPONSE ==="); - print("Status Code: ${response.statusCode}"); - print("Response Headers: ${response.headers}"); - _printLongString("Response Body:", response.body); - print("==================="); - - return handleResponse(response); - }); - } finally { - // client.close(); - } - } - - Future delete(Uri url, {Map? headers}) async { - try { - // Get authenticated headers (merge with provided headers) - Map finalHeaders = await _getAuthenticatedHeaders(headers); - - // Log request details - print("=== DELETE REQUEST ==="); - print("URL: $url"); - print("Headers: $finalHeaders"); - print("====================="); - - return client - .delete(url, headers: finalHeaders) - .then((http.Response response) { - // Log response details - print("=== DELETE RESPONSE ==="); - print("Status Code: ${response.statusCode}"); - print("Response Headers: ${response.headers}"); - _printLongString("Response Body:", response.body); - print("======================"); - - return handleResponse(response); - }); - } finally { - // client.close(); - } - } - - http.Response handleResponse(http.Response response) { - return response; - } - - // Future get(String url, {Map headers, Map queryParameters}) async { - // _connectivityResult = await (Connectivity().checkConnectivity()); - // if(_connectivityResult == ConnectivityResult.none) { - // response = Response( - // data: { - // 'message' : 'Please check internet connection' - // }, - // statusCode: 0 - // ); - // } else { - // response = await dio.get(url, options: Options(headers: headers), queryParameters: queryParameters); - // } - // return handleResponse(response); - // } -} diff --git a/lib/services/tasks_service.dart b/lib/services/tasks_service.dart new file mode 100644 index 0000000..b96611f --- /dev/null +++ b/lib/services/tasks_service.dart @@ -0,0 +1,176 @@ +import 'package:flutter/foundation.dart'; +import '../config/api_config.dart'; +import '../models/api_models.dart'; +import 'api_service.dart'; + +class TasksService { + final ApiService _apiService = ApiService(); + + Future getTasks({ + String? status, + String? priority, + String? ownerId, + String? accountId, + String? contactId, + int limit = 10, + int offset = 0, + }) async { + try { + final Map queryParams = {}; + + if (status != null) queryParams['status'] = status; + if (priority != null) queryParams['priority'] = priority; + if (ownerId != null) queryParams['ownerId'] = ownerId; + if (accountId != null) queryParams['accountId'] = accountId; + if (contactId != null) queryParams['contactId'] = contactId; + queryParams['limit'] = limit.toString(); + queryParams['offset'] = offset.toString(); + + final response = await _apiService.get( + ApiConfig.tasks, + queryParams: queryParams, + ); + + if (response.success && response.data != null) { + return TasksResponse.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('Error getting tasks: $e'); + return null; + } + } + + Future getTaskById(String taskId) async { + try { + final response = await _apiService.get( + ApiConfig.replacePathParam(ApiConfig.taskById, 'id', taskId), + ); + + if (response.success && response.data != null) { + return Task.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('Error getting task by ID: $e'); + return null; + } + } + + Future createTask({ + required String subject, + String? description, + String? status, + String? priority, + DateTime? dueDate, + String? ownerId, + String? accountId, + String? contactId, + }) async { + try { + final Map data = { + 'subject': subject, + if (description != null) 'description': description, + if (status != null) 'status': status, + if (priority != null) 'priority': priority, + if (dueDate != null) 'dueDate': dueDate.toIso8601String(), + if (ownerId != null) 'ownerId': ownerId, + if (accountId != null) 'accountId': accountId, + if (contactId != null) 'contactId': contactId, + }; + + final response = await _apiService.post(ApiConfig.tasks, data); + + if (response.success && response.data != null) { + return Task.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('Error creating task: $e'); + return null; + } + } + + Future updateTask( + String taskId, { + String? subject, + String? description, + String? status, + String? priority, + DateTime? dueDate, + String? ownerId, + String? accountId, + String? contactId, + }) async { + try { + final Map data = {}; + + if (subject != null) data['subject'] = subject; + if (description != null) data['description'] = description; + if (status != null) data['status'] = status; + if (priority != null) data['priority'] = priority; + if (dueDate != null) data['dueDate'] = dueDate.toIso8601String(); + if (ownerId != null) data['ownerId'] = ownerId; + if (accountId != null) data['accountId'] = accountId; + if (contactId != null) data['contactId'] = contactId; + + final response = await _apiService.put( + ApiConfig.replacePathParam(ApiConfig.taskById, 'id', taskId), + data, + ); + + if (response.success && response.data != null) { + return Task.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('Error updating task: $e'); + return null; + } + } + + Future deleteTask(String taskId) async { + try { + final response = await _apiService.delete( + ApiConfig.replacePathParam(ApiConfig.taskById, 'id', taskId), + ); + + return response.success; + } catch (e) { + debugPrint('Error deleting task: $e'); + return false; + } + } + + Future searchTasks({ + required String query, + String? status, + String? priority, + int limit = 10, + int offset = 0, + }) async { + try { + final Map queryParams = { + 'q': query, + 'limit': limit.toString(), + 'offset': offset.toString(), + }; + + if (status != null) queryParams['status'] = status; + if (priority != null) queryParams['priority'] = priority; + + final response = await _apiService.get( + ApiConfig.taskSearch, + queryParams: queryParams, + ); + + if (response.success && response.data != null) { + return TasksResponse.fromJson(response.data!); + } + return null; + } catch (e) { + debugPrint('Error searching tasks: $e'); + return null; + } + } +} diff --git a/lib/ui/screens/accounts/account_create.dart b/lib/ui/screens/accounts/account_create.dart deleted file mode 100644 index ff383e7..0000000 --- a/lib/ui/screens/accounts/account_create.dart +++ /dev/null @@ -1,1437 +0,0 @@ -import 'dart:io'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -import 'package:textfield_tags/textfield_tags.dart'; - -class CreateAccount extends StatefulWidget { - CreateAccount(); - @override - State createState() => _CreateAccountState(); -} - -class _CreateAccountState extends State { - int _currentTabIndex = 0; - quill.QuillController _controller = quill.QuillController.basic(); - TextEditingController _descriptionController = TextEditingController(); - GlobalKey _accountFormKey = GlobalKey(); - GlobalKey _addressFormKey = GlobalKey(); - TextEditingController fileNameController = new TextEditingController(); - TextfieldTagsController _tagsController = TextfieldTagsController(); - - List _accountFormKeys = [ - "name", - "phone", - "email", - "contacts", - "website", - "lead", - "assigned_to", - "status", - "account_attachment", - "tags" - ]; - List _addressFormKeys = [ - "billing_address_line", - "billing_street", - "billing_city", - "billing_state", - "billing_postcode", - "billing_country" - ]; - Map _errors = {}; - bool _isLoading = false; - File? file = File(''); - - @override - void initState() { - super.initState(); - } - - @override - void dispose() { - super.dispose(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _filePicker() async { - FilePickerResult? result = - await FilePicker.platform.pickFiles(allowMultiple: false); - if (result != null) { - file = File(result.files[0].path!); - var _filename = file!.path.toString(); - var split = _filename.split('/'); - Map values = { - for (int i = 0; i < split.length; i++) i: split[i] - }; - setState(() { - fileNameController.text = values[7].toString(); - }); - } else {} - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_accountFormKey.currentState != null) - _accountFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: buildaccountBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 0; - }); - }, - child: buildAddressBlock()); - } else if (_currentTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildDescriptionBlock()); - } - } - - Widget buildaccountBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _accountFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - accountBloc.currentEditAccount['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount['name'] = - value; - }, - ), - ), - _errors['name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Website ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - accountBloc.currentEditAccount['website'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - hintText: 'https://www.bottlecrm.com', - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.url, - onSaved: (value) { - accountBloc.currentEditAccount['website'] = - value; - }), - ), - _errors['website'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['website'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Phone Number ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - accountBloc.currentEditAccount['phone'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - hintText: '+91XXXXXXXXXX', - ), - keyboardType: TextInputType.phone, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount['phone'] = - value; - }, - ), - ), - _errors['phone'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['phone'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Email Address ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - accountBloc.currentEditAccount['email'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - if (value.isNotEmpty && - !RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(value)) { - return 'Enter valid email address.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount['email'] = - value; - }, - ), - ), - _errors['email'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['email'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Leads ", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.leadsTitles.cast(), - onChanged: print, - onSaved: (selection) { - if (selection == null) { - accountBloc.currentEditAccount['lead'] = ""; - } else { - accountBloc.currentEditAccount['lead'] = - selection; - } - }, - selectedItem: - accountBloc.currentEditAccount['lead'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Lead", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: - accountBloc.currentEditAccount['teams'], - // validator: (value) { - // if (value.length == 0) { - // return 'Please select one or more options'; - // } - // return null; - // }, - onSaved: (value) { - if (value == null) return; - accountBloc.currentEditAccount['teams'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Contacts ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: - accountBloc.currentEditAccount['contacts'], - onSaved: (value) { - if (value == null) return; - accountBloc.currentEditAccount['contacts'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned To", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "users", - ), - initialValue: accountBloc - .currentEditAccount['assigned_to'], - onSaved: (value) { - if (value == null) return; - accountBloc - .currentEditAccount['assigned_to'] = - value; - }), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Status", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownButtonFormField( - decoration: InputDecoration( - border: boxBorder(), - contentPadding: EdgeInsets.all(12.0)), - style: TextStyle(color: Colors.black), - hint: Text('select Status'), - value: accountBloc.currentEditAccount['status'], - onChanged: (value) { - accountBloc.currentEditAccount['status'] = - value; - }, - items: ['open', 'close'].map((item) { - return DropdownMenuItem( - child: new Text(item), - value: item, - ); - }).toList(), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Attachment", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: fileNameController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: _filePicker, - icon: Icon(Icons.upload))), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Tags", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - TextFormField( - decoration: InputDecoration( - isDense: true, - border: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - hintText: "Enter tags separated by comma...", - ), - maxLines: 2, - onChanged: (value) { - // TODO: Handle tags parsing - }, - ), - ])), - ]))))); - } - - Widget buildAddressBlock() { - return SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _addressFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Billing Address Line ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: accountBloc - .currentEditAccount['billing_address_line'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount[ - 'billing_address_line'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Street ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: accountBloc - .currentEditAccount['billing_street'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount['billing_street'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Postal Code ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: accountBloc - .currentEditAccount['billing_postcode'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc - .currentEditAccount['billing_postcode'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'City ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - accountBloc.currentEditAccount['billing_city'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount['billing_city'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'State ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - accountBloc.currentEditAccount['billing_state'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - accountBloc.currentEditAccount['billing_state'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Country ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.countries, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - accountBloc - .currentEditAccount['billing_country'] = ""; - } else { - accountBloc - .currentEditAccount['billing_country'] = - selection; - } - }, - selectedItem: accountBloc - .currentEditAccount['billing_country'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Country", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - // Container( - // width: screenWidth * 0.92, - // child: DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: leadBloc.countries, - // onChanged: print, - // selectedItem: accountBloc - // .currentEditAccount['billing_country'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Country", - // )), - // popupTitle: Container( - // decoration: BoxDecoration( - // color: Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'County', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // validator: (value) { - // if (value == null || value.isEmpty) { - // return 'This field is required.'; - // } - // return null; - // }, - // onSaved: (newValue) { - // accountBloc - // .currentEditAccount['billing_country'] = - // newValue; - // }, - // )), - ])) - ])))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Container( - padding: EdgeInsets.all(8.0), - child: TextFormField( - controller: _descriptionController, - maxLines: 10, - decoration: InputDecoration( - hintText: 'Enter description...', - border: OutlineInputBorder(), - ), - enabled: !_isLoading, - ), - ) - ], - )); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - accountBloc.resetAccountFields(); - accountBloc.currentEditAccountId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - accountBloc.currentEditAccountId == "" - ? 'Add account' - : 'Edit account', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_accountFormKey.currentState != null) - _accountFormKey.currentState!.save(); - accountBloc.currentEditAccount['tags'] = - _tagsController.getTags; - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - accountBloc.currentEditAccount['description'] = - _controller.document.toPlainText(); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 0; - }); - }, - child: !_isLoading - ? Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Account', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ) - : Container(), - ), - GestureDetector( - onTap: () { - if (_accountFormKey.currentState != null) - _accountFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: !_isLoading - ? Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Address', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ) - : Container(), - ), - GestureDetector( - onTap: () { - if (_accountFormKey.currentState != null) - _accountFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 2; - }); - }, - child: !_isLoading - ? Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ) - : Container(), - ), - ], - ), - ), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_accountFormKey.currentState != null) { - if (!_accountFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _accountFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_addressFormKey.currentState != null) { - if (!_addressFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _addressFormKey.currentState!.save(); - Map _result = {}; - if (accountBloc.currentEditAccountId != null && - accountBloc.currentEditAccountId != "") { - _result = await accountBloc.editAccount(); - } else { - _result = await accountBloc.createAccount(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - accountBloc.resetAccountFields(); - accountBloc.currentEditAccountId = ""; - showToaster(_result['message'], context); - accountBloc.openAccounts.clear(); - accountBloc.closedAccounts.clear(); - await accountBloc.fetchAccounts(); - await FirebaseAnalytics.instance.logEvent(name: "Account_Created"); - Navigator.pushReplacementNamed(context, '/accounts_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _accountFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - for (var key in _addressFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 1; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - } - - showErrorMessage(BuildContext context, String msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/accounts/account_details.dart b/lib/ui/screens/accounts/account_details.dart deleted file mode 100644 index 1ee0a09..0000000 --- a/lib/ui/screens/accounts/account_details.dart +++ /dev/null @@ -1,789 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class AccountDetails extends StatefulWidget { - AccountDetails(); - @override - State createState() => _AccountDetailsState(); -} - -class _AccountDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Account Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - accountBloc.currentEditAccountId = - accountBloc.currentAccount!.id.toString(); - await accountBloc.updateCurrentEditAccount( - accountBloc.currentAccount!); - Navigator.pushNamed(context, '/account_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Account Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Attachment', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.21, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: !_isLoading - ? Container( - child: buildTopBar(), - color: Colors.white, - ) - : Container( - height: screenHeight, - width: screenWidth, - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildAccountInfoBlock(); - } else if (_currentTabIndex == 1) { - return buildAttachmentBlock(); - } else if (_currentTabIndex == 2) { - return buildDescriptionBlock(); - } - } - - buildAttachmentBlock() { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - height: screenHeight, - width: screenWidth, - color: Colors.white, - alignment: Alignment.center, - child: Text("No Attachments Found."), - ), - ); - } - - buildDescriptionBlock() { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - height: screenHeight, - width: screenWidth, - alignment: Alignment.center, - color: Colors.white, - child: Text( - accountBloc.currentAccount!.description != "" - ? accountBloc.currentAccount!.description! - : "No Description Found", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22.0)), - ), - ); - } - - buildAccountInfoBlock() { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Text( - accountBloc.currentAccount!.name!.capitalizeFirstofEach(), - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 10.0), - TagViewWidget(accountBloc.currentAccount!.tags!), - SizedBox(height: 10.0), - ProfilePicViewWidget(accountBloc.currentAccount!.assignedTo! - .map((assignedUser) => assignedUser.profileUrl == "" - ? assignedUser.firstName![0].inCaps - : assignedUser.profileUrl) - .toList()) - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Container( - child: Text( - "Create Date", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Text( - accountBloc.currentAccount!.createdOn!, - style: TextStyle( - color: Colors.grey, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - ], - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - accountBloc.currentAccount!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${accountBloc.currentAccount!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.email_outlined, - size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - accountBloc.currentAccount!.email!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - accountBloc.currentAccount!.phone!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - // Row( - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: Image.asset( - // "assets/images/skype.png", - // width: screenWidth / 22, - // )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Text( - // " skype@Id", - // style: TextStyle( - // color: Colors.blue, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // ], - // ), - // SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Website :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - accountBloc.currentAccount!.website == "" - ? "------" - : accountBloc.currentAccount!.website!, - style: TextStyle( - color: accountBloc.currentAccount!.website == "" - ? Colors.black45 - : Colors.blue, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Lead :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - accountBloc.currentAccount!.lead != null && - accountBloc.currentAccount!.lead!.title != - null - ? accountBloc.currentAccount!.lead!.title! - : "------", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Industry :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - accountBloc.currentAccount!.industry == "" - ? "------" - : accountBloc.currentAccount!.industry!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Status :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - accountBloc.currentAccount!.status!, - style: TextStyle( - color: accountBloc.currentAccount!.status! - .toLowerCase() == - "open" - ? Colors.green - : Colors.red, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - ), - ), - SizedBox(height: 10), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column(children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Address :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "${accountBloc.currentAccount!.billingAddressLine!}, ${accountBloc.currentAccount!.billingStreet!}, ${accountBloc.currentAccount!.billingCity!}, ${accountBloc.currentAccount!.billingState!}, ${accountBloc.currentAccount!.billingCountry!}, ${accountBloc.currentAccount!.billingPostcode!}.", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ])), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteAccountAlertDialog( - context, accountBloc.currentAccount!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))), - ); - } - - void showDeleteAccountAlertDialog(BuildContext context, Account account) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - account.name != "" ? account.name!.capitalizeFirstofEach() : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this account?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteAccount(account); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteAccount(Account account) async { - setState(() { - _isLoading = true; - }); - Map result = await accountBloc.deleteAccount(account); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - accountBloc.openAccounts.clear(); - accountBloc.closedAccounts.clear(); - await accountBloc.fetchAccounts(); - await dashboardBloc.fetchDashboardDetails(); - await FirebaseAnalytics.instance.logEvent(name: "Account_Deleted"); - Navigator.pushReplacementNamed(context, '/accounts_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, result['message'].toString(), account); - } - } - - showErrorMessage(BuildContext context, msg, Account account) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteAccount(account); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/accounts/accounts_list.dart b/lib/ui/screens/accounts/accounts_list.dart deleted file mode 100644 index 3dae7cd..0000000 --- a/lib/ui/screens/accounts/accounts_list.dart +++ /dev/null @@ -1,699 +0,0 @@ -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; - -class AccountsList extends StatefulWidget { - AccountsList(); - @override - State createState() => _AccountsListState(); -} - -class _AccountsListState extends State { - var _currentTabIndex = 0; - final GlobalKey _filtersFormKey = GlobalKey(); - bool _isFilter = false; - List _activeAccounts = []; - List _inactiveAccounts = []; - Map _filtersFormData = {"name": "", "city": "", "tags": []}; - bool _isLoading = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - - @override - void initState() { - setState(() { - _activeAccounts = accountBloc.openAccounts; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - accountBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await accountBloc.fetchAccounts( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - accountBloc.offset = ""; - accountBloc.openAccounts.clear(); - accountBloc.closedAccounts.clear(); - await accountBloc.fetchAccounts( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter Name", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['name'] = value; - }, - ), - ), - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['city'], - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter City", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['city'] = value; - }, - ), - ), - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - margin: EdgeInsets.only(bottom: 5.0), - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: accountBloc.filterTags, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text("Tags"), - initialValue: _filtersFormData['tags'], - onSaved: (value) { - if (value == null) return; - _filtersFormData['tags'] = value; - }, - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "name": "", - "city": "", - "tags": [] - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - _inactiveAccounts = accountBloc.closedAccounts; - }); - }, - child: _buildOpenAccountsList()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: _buildClosedAccountsList()); - } - } - - Widget _buildOpenAccountsList() { - return _activeAccounts.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _activeAccounts.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - accountBloc.currentAccount = _activeAccounts[index]; - Navigator.pushNamed(context, '/account_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _activeAccounts[index] - .name! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Container( - width: screenWidth * 0.3, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - _activeAccounts[index] - .createdBy! - .profileUrl != - "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _activeAccounts[index] - .createdBy! - .profileUrl!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context) - .primaryColor, - child: Text( - _activeAccounts[index] - .createdBy! - .firstName![0] - .allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: - FontWeight.bold), - ), - ), - SizedBox(width: 5.0), - Text( - _activeAccounts[index] - .createdBy! - .firstName! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w500, - fontSize: screenWidth / 25)) - ], - ), - ) - ], - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.5, - child: TagViewWidget( - _activeAccounts[index].tags!)), - Text(_activeAccounts[index].createdOn!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ) - ], - ), - )); - }), - ) - : Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Open Accounts Found.'), - ); - } - - Widget _buildClosedAccountsList() { - return _inactiveAccounts.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _inactiveAccounts.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - accountBloc.currentAccount = _inactiveAccounts[index]; - Navigator.pushNamed(context, '/account_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _inactiveAccounts[index] - .name! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Container( - width: screenWidth * 0.3, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - _inactiveAccounts[index] - .createdBy! - .profileUrl != - "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _inactiveAccounts[index] - .createdBy! - .profileUrl!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context) - .primaryColor, - child: Text( - _inactiveAccounts[index] - .createdBy! - .firstName![0] - .allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: - FontWeight.bold), - ), - ), - SizedBox(width: 5.0), - Text( - _inactiveAccounts[index] - .createdBy! - .firstName! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w500, - fontSize: screenWidth / 25)) - ], - ), - ) - ], - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.5, - child: TagViewWidget( - _inactiveAccounts[index].tags!)), - Text(_inactiveAccounts[index].createdOn!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ) - ], - ), - )); - }), - ) - : Container( - height: screenHeight, - width: screenWidth, - color: Colors.white, - alignment: Alignment.center, - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Closed Accounts Found.'), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - Navigator.pushReplacementNamed( - context, "/dashboard"); - currentBottomNavigationIndex="0"; - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Accounts', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - if (_currentTabIndex != 0) { - setState(() { - _currentTabIndex = 0; - _activeAccounts = - accountBloc.openAccounts; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Open', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - if (_currentTabIndex != 1) { - setState(() { - _currentTabIndex = 1; - _inactiveAccounts = - accountBloc.closedAccounts; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Closed', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ) - ], - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, - child: buildTopBar(), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - accountBloc.currentEditAccountId = ""; - if (accountBloc.openAccounts.length == 0) { - showAlertDialog(context); - } else { - Navigator.pushNamed(context, '/account_create'); - } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any accounts, Please create account first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/account_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/authentication/change_password.dart b/lib/ui/screens/authentication/change_password.dart deleted file mode 100644 index 3732ddd..0000000 --- a/lib/ui/screens/authentication/change_password.dart +++ /dev/null @@ -1,407 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class ChangePassword extends StatefulWidget { - ChangePassword(); - @override - State createState() => _ChangePasswordState(); -} - -class _ChangePasswordState extends State { - final GlobalKey _formKey = GlobalKey(); - bool _isPasswordVisible = false; - bool _isConfirmPasswordVisible = false; - bool _isOldPasswordVisible = false; - Map _formData = { - "old_password": "", - "new_password": "", - "retype_password": "" - }; - bool _isLoading = false; - String _errorMessage = ''; - Map _errors = {}; - - @override - void initState() { - super.initState(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - borderSide: BorderSide(width: 1, color: Colors.black12), - ); - } - - _submitForm() async { - if (!_formKey.currentState!.validate()) { - return; - } - _formKey.currentState!.save(); - if (_formData['new_password'] != _formData['retype_password']) { - setState(() { - _errorMessage = "Confirm password do not match with new password"; - }); - return; - } - setState(() { - _isLoading = true; - }); - Map result = await authBloc.changePassword(_formData); - if (result['error'] == false) { - setState(() { - _errorMessage = ''; - }); - showToaster('Password changed successfully.', context); - await FirebaseAnalytics.instance.logEvent(name: "Password_Changes"); - Navigator.pop(context); - } else if (result['error'] == true) { - if (result['message'] != null) { - setState(() { - _errorMessage = result['message']; - }); - } - if (result['errors'] != null) { - if (result['errors']['retype_password'] != null) { - result['errors']['retype_password'] = - "New Password and Confirm Password did not match."; - } - setState(() { - _errors = result['errors']; - }); - } - } else { - setState(() { - _errorMessage = ''; - }); - showErrorMessage(context,result['message'].toString()); - } - setState(() { - _isLoading = false; - }); - } - - showErrorMessage(BuildContext context,String message) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(message), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - IconButton( - icon: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onPressed: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Change Password', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - ], - ), - ), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - ), - child: buildPasswordScreen(), - )) - ], - ), - ), - ), - ); - } - - buildPasswordScreen() { - return Container( - height: screenHeight, - alignment: Alignment.center, - padding: EdgeInsets.all(20.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: Form( - key: _formKey, - child: Column( - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Old Password', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: - _isOldPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context).primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isOldPasswordVisible = - !_isOldPasswordVisible; - }); - }, - icon: Icon( - _isOldPasswordVisible - ? Icons.visibility_outlined - : Icons.visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _formData['old_password'] = value; - }, - ), - ), - _errors['old_password'] != null - ? Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only( - bottom: 10.0, left: 10.0), - child: Text( - _errors['old_password'], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.02), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('New Password', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: _isPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context).primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isPasswordVisible = - !_isPasswordVisible; - }); - }, - icon: Icon( - _isPasswordVisible - ? Icons.visibility_outlined - : Icons.visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _formData['new_password'] = value; - }, - ), - ), - _errors['new_password'] != null - ? Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only( - bottom: 10.0, left: 10.0), - child: Text( - _errors['new_password'], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.02), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Confirm Password', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: - _isConfirmPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context).primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isConfirmPasswordVisible = - !_isConfirmPasswordVisible; - }); - }, - icon: Icon( - _isConfirmPasswordVisible - ? Icons.visibility_outlined - : Icons.visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _formData['retype_password'] = value; - }, - ), - ), - _errors['retype_password'] != null - ? Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only( - bottom: 10.0, left: 10.0), - child: Text( - _errors['retype_password'], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ], - ), - ), - _errorMessage != '' - ? Container( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - SizedBox(height: 10.0), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - _errorMessage = ''; - _errors = {}; - _submitForm(); - }, - child: Text( - 'Submit', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 22), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: new AlwaysStoppedAnimation( - Color.fromRGBO(62, 121, 247, 1))), - ) - ], - )), - ), - ], - )); - } -} diff --git a/lib/ui/screens/authentication/companies_List.dart b/lib/ui/screens/authentication/companies_List.dart deleted file mode 100644 index 942f898..0000000 --- a/lib/ui/screens/authentication/companies_List.dart +++ /dev/null @@ -1,189 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; - -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:bottle_crm/model/organization.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; - -class CompaniesList extends StatefulWidget { - CompaniesList(); - @override - State createState() => _CompaniesListState(); -} - -class _CompaniesListState extends State { - List companies = []; - bool _isLoading = false; - - @override - void initState() { - setState(() { - companies = authBloc.companies; - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return PopScope( - onPopInvokedWithResult: (didPop, result) async { - if (!didPop) { - bool shouldPop = await onWillPop(); - if (shouldPop) Navigator.of(context).pop(); - } - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric( - horizontal: 25.0, vertical: 15.0), - child: Text( - 'Companies List', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ), - Expanded( - child: Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - color: Colors.white, - ), - child: companies.length != 0 - ? Container( - child: ListView.builder( - itemCount: companies.length, - physics: - const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: - (BuildContext context, int index) { - return GestureDetector( - onTap: () async { - if (!_isLoading) { - setState(() { - _isLoading = true; - }); - final SharedPreferences - preferences = - await SharedPreferences - .getInstance(); - preferences.setString( - 'org', - companies[index].id!); - authBloc.selectedOrganization = - companies[index]; - await fetchRequiredData(); - setState(() { - _isLoading = false; - }); - await FirebaseAnalytics.instance - .logEvent( - name: - "${companies[index].name!}_Selected"); - Navigator.pushNamed( - context, '/dashboard'); - } - }, - child: Container( - margin: - EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - color: Colors.grey[100], - border: Border.all( - width: 1.0, - color: Colors.grey), - borderRadius: BorderRadius.all( - Radius.circular(5.0)), - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment - .spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - companies[index].name!, - style: TextStyle( - color: - bottomNavBarSelectedTextColor, - fontSize: - screenWidth / 24, - fontWeight: - FontWeight.bold), - ), - SizedBox(height: 4), - Container( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: companies[index].role == 'ADMIN' - ? Colors.blue.withOpacity(0.1) - : Colors.grey.withOpacity(0.1), - borderRadius: BorderRadius.circular(10), - border: Border.all( - color: companies[index].role == 'ADMIN' - ? Colors.blue.withOpacity(0.3) - : Colors.grey.withOpacity(0.3) - ) - ), - child: Text( - companies[index].role ?? 'USER', - style: TextStyle( - color: companies[index].role == 'ADMIN' - ? Colors.blue[700] - : Colors.grey[700], - fontSize: screenWidth / 32, - fontWeight: FontWeight.w500 - ), - ), - ), - ], - ), - ), - Container( - child: Icon( - Icons.arrow_forward_ios, - color: - bottomNavBarSelectedTextColor, - size: screenWidth / 20, - )) - ], - ))); - }), - ) - : Center( - child: Text('No data found.'), - ), - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ), - ], - )), - ); - } -} diff --git a/lib/ui/screens/authentication/forgot_password.dart b/lib/ui/screens/authentication/forgot_password.dart deleted file mode 100644 index c7d302d..0000000 --- a/lib/ui/screens/authentication/forgot_password.dart +++ /dev/null @@ -1,381 +0,0 @@ -import 'package:bottle_crm/responsive.dart'; -import 'package:bottle_crm/utils/validations.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:flutter_svg/svg.dart'; - -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class ForgotPassword extends StatefulWidget { - ForgotPassword(); - @override - State createState() => _ForgotPasswordState(); -} - -class _ForgotPasswordState extends State { - final GlobalKey _forgotPasswordFormKey = GlobalKey(); - String? _email = ''; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - borderSide: BorderSide(width: 1, color: Colors.black12), - ); - } - - _submitForm() async { - if (!_forgotPasswordFormKey.currentState!.validate()) { - return; - } - _forgotPasswordFormKey.currentState!.save(); - setState(() { - _isLoading = true; - }); - Map result = await authBloc.forgotPassword({'email': _email}); - if (result['error'] == false) { - await authBloc.fetchCompanies(); - await FirebaseAnalytics.instance.logEvent(name: "Forget Password"); - Navigator.pushNamedAndRemoveUntil( - context, '/dashboard', (route) => false); - } else if (result['error'] == true) { - // Handle error case - could show a dialog or snackbar - } else { - showErrorMessage(context, result['message'].toString()); - } - setState(() { - _isLoading = false; - }); - } - - showErrorMessage(BuildContext context, String message) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text('Something went wrong'), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } - - Widget forgotPasswordWidget() { - return Responsive( - mobile: buildMobileScreen(), - tablet: buildTabletScreen(), - desktop: Container()); - } - - buildMobileScreen() { - return Column( - children: [ - SizedBox(height: screenHeight * 0.1), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - ), - width: screenWidth, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Forgot Password', - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: screenWidth / 18), - ), - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.3, - ) - ], - ), - ), - Container( - child: Form( - key: _forgotPasswordFormKey, - child: Column( - children: [ - Container( - child: Text( - 'Please enter your email address below and we will send you information to change your password.', - style: TextStyle( - color: Colors.grey[700], - fontSize: screenWidth / 27, - fontWeight: FontWeight.w600), - )), - SizedBox(height: 10.0), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Email ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.email_outlined, - color: Theme.of(context) - .primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.emailAddress, - validator: (value) =>FieldValidators.emailFieldValidation(value!), - onSaved: (value) { - _email = value; - }, - ), - ), - ], - ), - ), - SizedBox(height: screenHeight * 0.02), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - 'Submit', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 22), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: - new AlwaysStoppedAnimation( - Color.fromRGBO( - 62, 121, 247, 1))), - ) - ], - )), - ), - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Back to ", - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 24), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/login'); - }, - child: Text( - 'Login', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontSize: screenWidth / 24), - ), - ) - ], - )) - ], - ), - ), - ), - ), - ], - ); - } - - buildTabletScreen() { - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topLeft: Radius.circular(50.0))), - height: screenHeight * 0.9, - width: screenWidth, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Forgot Password', - style: TextStyle( - color: Colors.black54, fontSize: screenWidth / 26), - ), - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.2, - ) - ], - ), - ), - Container( - width: screenWidth * 0.6, - child: Form( - key: _forgotPasswordFormKey, - child: Column( - children: [ - Container( - child: Text( - 'Please enter your email address below and we will send you information to change your password.', - style: TextStyle( - color: Colors.grey[700], - fontSize: screenWidth / 42, - fontWeight: FontWeight.w600), - )), - SizedBox(height: 10.0), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Email', - style: TextStyle( - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.email_outlined, - color: Theme.of(context).primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _email = value; - }, - ), - ), - ], - ), - ), - SizedBox(height: screenHeight * 0.02), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - 'Submit', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 35), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: new AlwaysStoppedAnimation( - Color.fromRGBO(62, 121, 247, 1))), - ) - ], - )), - ), - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Back to ", - style: - TextStyle(color: Colors.grey, fontSize: screenWidth / 40), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/login'); - }, - child: Text( - 'Login', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontSize: screenWidth / 40), - ), - ) - ], - )), - SizedBox(height: screenHeight * 0.05) - ], - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: Container( - decoration: BoxDecoration( - color: Color.fromRGBO(73, 128, 255, 1.0) - ), - child: forgotPasswordWidget()), - ); - } -} diff --git a/lib/ui/screens/authentication/login.dart b/lib/ui/screens/authentication/login.dart deleted file mode 100644 index 2d07451..0000000 --- a/lib/ui/screens/authentication/login.dart +++ /dev/null @@ -1,489 +0,0 @@ -import 'package:bottle_crm/responsive.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:flutter_svg/svg.dart'; - -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class Login extends StatefulWidget { - Login(); - @override - State createState() => _LoginState(); -} - -class _LoginState extends State { - bool _isLoading = false; - String _errorMessage = ''; - - @override - void initState() { - super.initState(); - // Clear all stored data when login page opens - authBloc.clearAllStoredData(); - } - - - _googleLogin() async { - setState(() { - _isLoading = true; - }); - - try { - Map result = await authBloc.googleLogin(); - if (result['error'] == false) { - setState(() { - _errorMessage = ''; - }); - await FirebaseAnalytics.instance.logEvent(name: "google_login"); - Navigator.pushNamedAndRemoveUntil( - context, '/companies_List', (route) => false); - } else { - setState(() { - _errorMessage = result['message'] ?? 'Google login failed'; - }); - } - } catch (e) { - setState(() { - _errorMessage = 'Google login failed. Please try again.'; - }); - } - - setState(() { - _isLoading = false; - }); - } - - - Widget loginWidget() { - return Responsive( - mobile: buildMobileScreen(), - tablet: buildTabletScreen(), - desktop: Container()); - } - - buildMobileScreen() { - return SingleChildScrollView( - child: Container( - height: screenHeight, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Theme.of(context).primaryColor, - Theme.of(context).primaryColor.withOpacity(0.8), - ], - ), - ), - child: Column( - children: [ - SizedBox(height: screenHeight * 0.08), - // Logo and Branding Section - Container( - padding: EdgeInsets.symmetric(horizontal: 30.0), - child: Column( - children: [ - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.4, - color: Colors.white, - ), - SizedBox(height: 20), - Text( - 'BottleCRM', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 10, - fontWeight: FontWeight.bold, - letterSpacing: 1.2, - ), - ), - SizedBox(height: 10), - Text( - 'Free CRM for startups and enterprises', - style: TextStyle( - color: Colors.white.withOpacity(0.9), - fontSize: screenWidth / 25, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - SizedBox(height: screenHeight * 0.08), - // Login Card - Expanded( - child: Container( - width: screenWidth, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(30), - topRight: Radius.circular(30), - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 20, - offset: Offset(0, -5), - ), - ], - ), - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Welcome Back!', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 12, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 10), - Text( - 'Sign in to continue managing your business', - style: TextStyle( - color: Colors.grey[600], - fontSize: screenWidth / 26, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: screenHeight * 0.05), - _errorMessage != '' - ? Container( - margin: EdgeInsets.only(bottom: 20.0), - padding: EdgeInsets.all(12.0), - decoration: BoxDecoration( - color: Colors.red.withOpacity(0.1), - borderRadius: BorderRadius.circular(8.0), - border: Border.all(color: Colors.red.withOpacity(0.3)), - ), - child: Row( - children: [ - Icon(Icons.error_outline, color: Colors.red, size: 20), - SizedBox(width: 8), - Expanded( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red[700], - fontSize: screenWidth / 30, - ), - ), - ), - ], - ), - ) - : SizedBox(), - !_isLoading - ? Container( - width: screenWidth, - height: 56, - child: ElevatedButton( - onPressed: _googleLogin, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black87, - elevation: 2, - shadowColor: Colors.black26, - side: BorderSide(color: Colors.grey[300]!, width: 1), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/google-icon.png', - width: 24, - height: 24, - ), - SizedBox(width: 16), - Text( - 'Continue with Google', - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ) - : Container( - height: 56, - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Theme.of(context).primaryColor), - ), - ), - ), - SizedBox(height: screenHeight * 0.04), - Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.withOpacity(0.05), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.blue.withOpacity(0.2)), - ), - child: Row( - children: [ - Icon(Icons.info_outline, color: Colors.blue, size: 20), - SizedBox(width: 8), - Expanded( - child: Text( - 'Secure sign-in powered by Google OAuth 2.0', - style: TextStyle( - color: Colors.blue[700], - fontSize: screenWidth / 32, - ), - ), - ), - ], - ), - ), - SizedBox( - height: screenHeight * 0.05, - ), - ], - ), - ), - ), - ), - ], - ), - ), - ); - } - - buildTabletScreen() { - return Container( - height: screenHeight, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Theme.of(context).primaryColor, - Theme.of(context).primaryColor, - ], - ), - ), - child: Row( - children: [ - // Left side - Branding - Expanded( - flex: 1, - child: Container( - padding: EdgeInsets.all(40), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.15, - colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), - ), - SizedBox(height: 30), - Text( - 'BottleCRM', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold, - letterSpacing: 1.2, - ), - ), - SizedBox(height: 15), - Text( - 'Free CRM for startups and enterprises', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 50, - fontWeight: FontWeight.w400, - height: 1.5, - ), - ), - SizedBox(height: 30), - Text( - 'Manage your customers, leads, and opportunities all in one place.', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 60, - height: 1.6, - ), - ), - ], - ), - ), - ), - // Right side - Login Form - Expanded( - flex: 1, - child: Container( - margin: EdgeInsets.all(40), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.black12, - blurRadius: 20, - offset: Offset(0, 10), - ), - ], - ), - child: Container( - padding: EdgeInsets.all(40), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Welcome Back!', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 25, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 10), - Text( - 'Sign in to continue managing your business', - style: TextStyle( - color: Colors.grey[600], - fontSize: screenWidth / 55, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: 40), - _errorMessage != '' - ? Container( - margin: EdgeInsets.only(bottom: 20.0), - padding: EdgeInsets.all(12.0), - decoration: BoxDecoration( - color: Colors.red.shade50, - borderRadius: BorderRadius.circular(8.0), - border: Border.all(color: Colors.red.shade200), - ), - child: Row( - children: [ - Icon(Icons.error_outline, color: Colors.red, size: 18), - SizedBox(width: 8), - Expanded( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red[700], - fontSize: screenWidth / 60, - ), - ), - ), - ], - ), - ) - : SizedBox(), - !_isLoading - ? Container( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: _googleLogin, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black87, - elevation: 2, - shadowColor: Colors.black26, - side: BorderSide(color: Colors.grey[300]!, width: 1), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/google-icon.png', - width: 24, - height: 24, - ), - SizedBox(width: 16), - Text( - 'Continue with Google', - style: TextStyle( - fontSize: screenWidth / 45, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ) - : Container( - height: 56, - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Theme.of(context).primaryColor), - ), - ), - ), - SizedBox(height: 30), - Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.shade50, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.blue.shade200), - ), - child: Row( - children: [ - Icon(Icons.info_outline, color: Colors.blue, size: 18), - SizedBox(width: 8), - Expanded( - child: Text( - 'Secure sign-in powered by Google OAuth 2.0', - style: TextStyle( - color: Colors.blue[700], - fontSize: screenWidth / 65, - ), - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - screenWidth = MediaQuery.of(context).size.width; - screenHeight = MediaQuery.of(context).size.height; - return Scaffold( - body: loginWidget(), - ); - } -} diff --git a/lib/ui/screens/authentication/profile.dart b/lib/ui/screens/authentication/profile.dart deleted file mode 100644 index fc4af5f..0000000 --- a/lib/ui/screens/authentication/profile.dart +++ /dev/null @@ -1,256 +0,0 @@ -import 'dart:core'; - -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class Profile extends StatefulWidget { - @override - State createState() => _ProfileState(); -} - -class _ProfileState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Profile', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.edit, - size: screenWidth / 20, - color: Theme.of(context).primaryColor), - GestureDetector( - onTap: () {}, - child: Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 20.0), - height: screenHeight * 0.2, - width: screenWidth, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - borderRadius: - BorderRadius.vertical(top: Radius.circular(20.0))), - child: Container( - child: authBloc.userProfile!.profileUrl != null && - authBloc.userProfile!.profileUrl != "" - ? CircleAvatar( - radius: screenWidth / 11.5, - backgroundColor: Theme.of(context).primaryColor, - child: CircleAvatar( - radius: screenWidth / 12, - backgroundImage: NetworkImage( - authBloc.userProfile!.profileUrl!), - backgroundColor: Colors.white, - ), - ) - : CircleAvatar( - radius: screenWidth / 20, - child: Text( - authBloc.userProfile!.firstName![0].allInCaps, - style: TextStyle( - fontSize: screenWidth / 11, - fontWeight: FontWeight.bold, - color: Theme.of(context).primaryColor), - ), - backgroundColor: Colors.grey[200], - ), - )), - Expanded( - child: Container( - padding: EdgeInsets.all(20.0), - color: Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Name', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w600, - color: bottomNavBarSelectedTextColor), - ), - SizedBox(height: 5.0), - authBloc.userProfile!.firstName! == "" && - authBloc.userProfile!.lastName! == "" - ? Text('------', - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w500, - color: bottomNavBarTextColor)) - : Text( - authBloc.userProfile!.firstName! + - ' ' + - authBloc.userProfile!.lastName!, - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w500, - color: bottomNavBarTextColor), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider(color: Colors.grey)), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Date of Joining', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w600, - color: bottomNavBarSelectedTextColor), - ), - SizedBox(height: 5.0), - authBloc.userProfile!.dateOfJoin! == '' - ? Text('------') - : Text( - authBloc.userProfile!.dateOfJoin! - .capitalizeFirstofEach(), - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w500, - color: bottomNavBarTextColor), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider(color: Colors.grey[200])), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Email Address', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w600, - color: bottomNavBarSelectedTextColor), - ), - SizedBox(height: 5.0), - Text( - authBloc.userProfile!.email!, - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w500, - color: bottomNavBarTextColor), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider(color: Colors.grey[200])), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Permissions', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w600, - color: bottomNavBarSelectedTextColor), - ), - SizedBox(height: 5.0), - Text( - authBloc.userProfile!.role!.toLowerCase() == "admin" - ? 'Sales and Marketing' - : authBloc.userProfile!.hasSalesAccess! && - authBloc - .userProfile!.hasMarketingAccess! - ? "Sales and Marketing" - : authBloc.userProfile!.hasSalesAccess! && - !authBloc.userProfile! - .hasMarketingAccess! - ? "Sales" - : !authBloc.userProfile! - .hasSalesAccess! && - authBloc.userProfile! - .hasMarketingAccess! - ? "Marketing" - : "------", - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w500, - color: bottomNavBarTextColor), - ) - ], - ), - ), - ], - ), - )) - ], - ), - ), - ), - ); - } -} diff --git a/lib/ui/screens/authentication/register.dart b/lib/ui/screens/authentication/register.dart deleted file mode 100644 index 372c26c..0000000 --- a/lib/ui/screens/authentication/register.dart +++ /dev/null @@ -1,929 +0,0 @@ -import 'package:bottle_crm/responsive.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:flutter_svg/svg.dart'; - -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class Register extends StatefulWidget { - Register(); - @override - State createState() => _RegisterState(); -} - -class _RegisterState extends State { - final GlobalKey _registerFormKey = GlobalKey(); - bool _isPasswordVisible = false; - Map _registerFormData = { - "company_name ": "", - "first_name ": "", - "email": "", - "password": "" - }; - bool _isLoading = false; - String _errorMessage = ''; - String _companyError = ''; - String _firstNameError = ""; - String _emailError = ''; - String _passwordError = ''; - - @override - void initState() { - super.initState(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(10)), - borderSide: BorderSide(width: 1, color: Colors.black12), - ); - } - - _submitForm() async { - if (!_registerFormKey.currentState!.validate()) { - return; - } - _registerFormKey.currentState!.save(); - setState(() { - _isLoading = true; - }); - Map result = await authBloc.register(_registerFormData); - if (result['error'] == false) { - setState(() { - _errorMessage = ''; - }); - await authBloc.fetchCompanies(); - await FirebaseAnalytics.instance.logEvent(name: "Sign_up"); - Navigator.pushNamedAndRemoveUntil( - context, '/dashboard', (route) => false); - } else if (result['error'] == true) { - setState(() { - _companyError = result['errors']['company_name'] != null - ? result['errors']['company_name'][0] - : ''; - _firstNameError = result['errors']['first_name'] != null - ? result['errors']['first_name'][0] - : ''; - _emailError = result['errors']['email'] != null - ? result['errors']['email'][0] - : ''; - _passwordError = result['errors']['password'] != null - ? result['errors']['password'][0] - : ''; - }); - } else { - setState(() { - _errorMessage = ''; - }); - showErrorMessage(context, result['message'].toString()); - } - setState(() { - _isLoading = false; - }); - } - - showErrorMessage(BuildContext context, String message) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(message), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } - - Widget registerWidget() { - return Responsive( - mobile: buildMobileScreen(), - tablet: buildTabletScreen(), - desktop: Container()); - } - - buildMobileScreen() { - return SingleChildScrollView( - child: Column( - children: [ - SizedBox(height: screenHeight * 0.1), - Container( - decoration: BoxDecoration( - color: Colors.white, - ), - width: screenWidth, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Register', - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.bold, - fontSize: screenWidth / 15), - ), - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.3, - ) - ], - ), - ), - SizedBox( - height: screenHeight * 0.03, - ), - Container( - child: Form( - key: _registerFormKey, - child: Column( - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Company Name ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.business, - color: Theme.of(context) - .primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['company_name'] = - value; - }, - ), - ), - _companyError != '' - ? Container( - child: Text( - _companyError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.01), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Name ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.person_outline, - color: Theme.of(context) - .primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['first_name'] = value; - }, - ), - ), - _firstNameError != '' - ? Container( - child: Text( - _firstNameError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.001), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Email ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.email_outlined, - color: Theme.of(context) - .primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['email'] = value; - }, - ), - ), - _emailError != '' - ? Container( - child: Text( - _emailError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.01), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - children: [ - TextSpan( - text: 'Password ', - style: TextStyle( - color: Colors.black, - fontSize: screenWidth / 24, - fontWeight: - FontWeight.w500)), - ], - ), - )), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: - _isPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context) - .primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isPasswordVisible = - !_isPasswordVisible; - }); - }, - icon: Icon( - _isPasswordVisible - ? Icons - .visibility_outlined - : Icons - .visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['password'] = value; - }, - ), - ), - _passwordError != '' - ? Container( - child: Text( - _passwordError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - ], - ), - ), - _errorMessage != '' - ? Container( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - setState(() { - _errorMessage = ''; - _companyError = ''; - _firstNameError = ''; - _emailError = ''; - _passwordError = ''; - }); - _submitForm(); - }, - child: Text( - 'Create Account', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 22), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: - new AlwaysStoppedAnimation( - Color.fromRGBO( - 62, 121, 247, 1))), - ) - ], - )), - ), - Container( - margin: EdgeInsets.symmetric(vertical: 20.0), - child: Text( - ' Or Connect With ', - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 3.0), - Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey[400]!), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: GestureDetector( - onTap: () {}, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('assets/images/google-icon.png', - width: screenWidth / 18), - SizedBox(width: 8.0), - Text( - 'Register With Google', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 24, - fontWeight: FontWeight.w600), - ) - ], - )), - ), - SizedBox( - height: screenHeight * 0.05, - ), - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Existing User? ", - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 24), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/login'); - }, - child: Text( - 'Login', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontSize: screenWidth / 24), - ), - ) - ], - )) - ], - ), - ), - ), - ], - ), - ); - } - - buildTabletScreen() { - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only(topLeft: Radius.circular(50.0))), - width: screenWidth, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 50.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Register', - style: TextStyle( - color: Colors.black54, fontSize: screenWidth / 24), - ), - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.2, - ) - ], - ), - ), - SizedBox( - height: screenHeight * 0.1, - ), - Container( - width: screenWidth * 0.5, - child: Form( - key: _registerFormKey, - child: Column( - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Company Name', - style: TextStyle( - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500)), - Container( - margin: - EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.person_outline, - color: Theme.of(context) - .primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['company_name'] = - value; - }, - ), - ), - _companyError != '' - ? Container( - child: Text( - _companyError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 28), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.01), - Text('First Name', - style: TextStyle( - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.person_outline, - color: Theme.of(context).primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['first_name'] = value; - }, - ), - ), - _firstNameError != '' - ? Container( - child: Text( - _firstNameError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 45), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.01), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Email', - style: TextStyle( - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - decoration: InputDecoration( - prefixIcon: Icon(Icons.email_outlined, - color: Theme.of(context).primaryColor), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['email'] = value; - }, - ), - ), - _emailError != '' - ? Container( - child: Text( - _emailError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 45), - ), - ) - : Container(), - ], - ), - ), - SizedBox(height: screenHeight * 0.01), - Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Password', - style: TextStyle( - fontSize: screenWidth / 40, - fontWeight: FontWeight.w500)), - Container( - margin: EdgeInsets.symmetric(vertical: 10.0), - child: TextFormField( - obscureText: _isPasswordVisible ? false : true, - decoration: InputDecoration( - prefixIcon: Icon(Icons.lock_outline, - color: Theme.of(context).primaryColor), - suffixIcon: IconButton( - onPressed: () { - setState(() { - _isPasswordVisible = - !_isPasswordVisible; - }); - }, - icon: Icon( - _isPasswordVisible - ? Icons.visibility_outlined - : Icons.visibility_off_outlined, - color: Colors.grey)), - contentPadding: EdgeInsets.all(12.0), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - fillColor: Colors.white, - filled: true, - hintStyle: TextStyle(fontSize: 14.0)), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - setState(() { - _errorMessage = ''; - }); - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - _registerFormData['password'] = value; - }, - ), - ), - _passwordError != '' - ? Container( - child: Text( - _passwordError, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 45), - ), - ) - : Container(), - ], - ), - ), - _errorMessage != '' - ? Container( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 45), - ), - ) - : Container(), - Container(height: 20.0), - !_isLoading - ? Container( - width: screenWidth, - child: ElevatedButton( - onPressed: () { - FocusScope.of(context).unfocus(); - setState(() { - _errorMessage = ''; - _companyError = ''; - _firstNameError = ''; - _emailError = ''; - _passwordError = ''; - }); - _submitForm(); - }, - child: Text( - 'Create Account', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 35), - )), - ) - : Container( - child: CircularProgressIndicator( - valueColor: new AlwaysStoppedAnimation( - Color.fromRGBO(62, 121, 247, 1))), - ) - ], - )), - ), - Container( - width: screenWidth * 0.5, - margin: EdgeInsets.symmetric(vertical: 30.0), - child: Text( - '-------------- Or Connect With --------------', - style: - TextStyle(color: Colors.grey, fontSize: screenWidth / 45), - ), - ), - SizedBox(height: 5.0), - Container( - width: screenWidth * 0.5, - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey[400]!), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: GestureDetector( - onTap: () {}, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset('assets/images/google-icon.png', - width: screenWidth / 25), - SizedBox(width: 8.0), - Text( - 'Register With Google', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 40, - fontWeight: FontWeight.w600), - ) - ], - )), - ), - SizedBox( - height: screenHeight * 0.05, - ), - Container( - width: screenWidth * 0.5, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Existing User? ", - style: TextStyle( - color: Colors.grey, fontSize: screenWidth / 40), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/login'); - }, - child: Text( - 'Sign In', - style: TextStyle( - color: Theme.of(context).primaryColor, - fontSize: screenWidth / 40), - ), - ) - ], - )), - SizedBox(height: screenHeight * 0.2) - ], - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: registerWidget()), - ); - } -} diff --git a/lib/ui/screens/cases/case_create.dart b/lib/ui/screens/cases/case_create.dart deleted file mode 100644 index f3a8cce..0000000 --- a/lib/ui/screens/cases/case_create.dart +++ /dev/null @@ -1,953 +0,0 @@ -import 'dart:io'; - -import 'package:bottle_crm/bloc/case_bloc.dart'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class CreateCase extends StatefulWidget { - CreateCase(); - @override - State createState() => _CreateCaseState(); -} - -class _CreateCaseState extends State { - TextEditingController _descriptionController = TextEditingController(); - final GlobalKey _caseFormKey = GlobalKey(); - TextEditingController _dateController = TextEditingController(); - TextEditingController fileNameController = new TextEditingController(); - String? selectedDate = ""; - DateTime initialDate = DateTime.now(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File? file = File(''); - List _caseFormKeys = [ - 'name', - 'status', - 'priority', - 'type_of_case', - 'account', - 'contacts', - 'closed_on', - 'description', - 'assigned_to', - 'teams', - ]; - - @override - void initState() { - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - super.initState(); - } - - _selectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: DateTime(1950), - lastDate: DateTime(2023), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - if (_caseFormKey.currentState != null) { - _caseFormKey.currentState!.save(); - } - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildCaseBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildDescriptionBlock()); - } - } - - Positioned buildReqField() { - return Positioned( - child: Container( - width: 3.0, - color: Colors.red, - ), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildCaseBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _caseFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: caseBloc.currentEditCase['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - caseBloc.currentEditCase['name'] = value; - }, - ), - ), - _errors['name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Status ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => caseBloc.statusObjForDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - caseBloc.currentEditCase['status'] = ""; - } else { - caseBloc.currentEditCase['status'] = - selection; - } - }, - selectedItem: - caseBloc.currentEditCase['status'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Satus", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['status'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['status'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Account ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.accountsObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - caseBloc.currentEditCase['account'] = ""; - } else { - caseBloc.currentEditCase['account'] = - selection; - } - }, - selectedItem: - caseBloc.currentEditCase['account'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Account", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['account'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['account'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Priority ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => caseBloc.priorityObjForDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - caseBloc.currentEditCase['priority'] = ""; - } else { - caseBloc.currentEditCase['priority'] = - selection; - } - }, - selectedItem: - caseBloc.currentEditCase['priority'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Priority", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['priority'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['priority'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Type Of Case", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => caseBloc.typeOfCaseObjForDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - caseBloc.currentEditCase['type_of_case'] = - ""; - } else { - caseBloc.currentEditCase['type_of_case'] = - selection; - } - }, - selectedItem: - caseBloc.currentEditCase['type_of_case'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a case type", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Contacts", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: - caseBloc.currentEditCase['contacts'], - onSaved: (value) { - if (value == null) return; - caseBloc.currentEditCase['contacts'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned to", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Assigned to", - ), - initialValue: - caseBloc.currentEditCase['assigned_to'], - onSaved: (value) { - if (value == null) return; - caseBloc.currentEditCase['assigned_to'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: - caseBloc.currentEditCase['teams'], - onSaved: (value) { - if (value == null) return; - caseBloc.currentEditCase['teams'] = value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Closed Date ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _dateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _selectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - print(value); - caseBloc.currentEditCase['closed_on'] = value; - }, - ), - ), - _errors['closed_on'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['closed_on'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Container( - padding: EdgeInsets.all(8.0), - child: TextFormField( - controller: _descriptionController, - maxLines: 10, - decoration: InputDecoration( - hintText: 'Enter description...', - border: OutlineInputBorder(), - ), - enabled: !_isLoading, - ), - )); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - caseBloc.cancelCurrentEditCase(); - caseBloc.currentEditCaseId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - caseBloc.currentEditCaseId == "" - ? 'Add Case' - : "Edit Case", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_caseFormKey.currentState != null) - _caseFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - // caseBloc.currentEditCase['description'] = - // _controller.document.toPlainText(); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Case', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_caseFormKey.currentState != null) - _caseFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_caseFormKey.currentState != null) { - if (!_caseFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _caseFormKey.currentState!.save(); - await Future.delayed(const Duration(seconds: 1), () async {}); - - Map _result = {}; - if (caseBloc.currentEditCaseId != null && - caseBloc.currentEditCaseId != "") { - _result = await caseBloc.editCase(); - } else { - _result = await caseBloc.createCase(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - caseBloc.cancelCurrentEditCase(); - caseBloc.currentEditCaseId = ""; - showToaster(_result['message'], context); - caseBloc.cases.clear(); - caseBloc.offset = ""; - await caseBloc.fetchCases(); - await FirebaseAnalytics.instance.logEvent(name: "Case_Created"); - Navigator.pushReplacementNamed(context, '/cases_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _caseFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/cases/case_details.dart b/lib/ui/screens/cases/case_details.dart deleted file mode 100644 index a15d41b..0000000 --- a/lib/ui/screens/cases/case_details.dart +++ /dev/null @@ -1,800 +0,0 @@ -import 'package:bottle_crm/bloc/case_bloc.dart'; -import 'package:bottle_crm/model/case.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; - -class CaseDetails extends StatefulWidget { - CaseDetails(); - @override - State createState() => _CaseDetailsState(); -} - -class _CaseDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Case Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - caseBloc.currentEditCaseId = - caseBloc.currentCase!.id.toString(); - await caseBloc - .updateCurrentEditCase(caseBloc.currentCase!); - Navigator.pushNamed(context, '/case_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Case Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.24, - child: Text( - 'Attachments', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.21, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: !_isLoading - ? Container( - child: buildTopBar(), - color: Colors.white, - ) - : Container( - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - if (_currentTabIndex == 0) { - setState(() { - _currentTabIndex = 1; - }); - } - }, - child: buildContactInfoBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - child: buildAttachmentBlock()); - } else if (_currentTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildDescriptionBlock()); - } - } - - buildAttachmentBlock() { - return Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text("No Attachment Found..."), - ); - } - - buildDescriptionBlock() { - return Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text( - caseBloc.currentCase!.description != "" - ? caseBloc.currentCase!.description! - : "No Description Found", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22.0)), - ); - } - - buildContactInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - caseBloc.currentCase!.name!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Container( - child: Row( - children: [ - CircleAvatar( - radius: screenWidth / 25, - backgroundImage: NetworkImage( - "https://www.thefamouspeople.com/profiles/images/virat-kohli-3.jpg"), - ), - SizedBox(width: 3.0), - CircleAvatar( - radius: screenWidth / 25, - backgroundImage: NetworkImage( - "https://upload.wikimedia.org/wikipedia/commons/2/29/Ms._Smriti_Mandhana%2C_Arjun_Awardee_%28Cricket%29%2C_in_New_Delhi_on_July_16%2C_2019_%28cropped%29.jpg"), - ), - SizedBox(width: 3.0), - CircleAvatar( - radius: screenWidth / 25, - backgroundColor: Colors.grey, - child: Text( - "JR", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ) - ], - ), - ), - ), - ], - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.name!.capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Account :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.account!.name != null - ? caseBloc.currentCase!.account!.name! - : "-----", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Status :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.status!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Closed Date :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.closedOn!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - )), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Priority :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.priority!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Type of Case :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - caseBloc.currentCase!.caseType == "" - ? "----" - : caseBloc.currentCase!.caseType!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - SizedBox(width: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.createdBy!.firstName!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(width: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - " +91 0000 000 000", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Text( - " +91 0000 000 000", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Teams :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.teams!.length == 0 - ? "----" - : _getteams(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Users :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - caseBloc.currentCase!.assignedTo!.length == 0 - ? "----" - : _getUsers(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteAccountAlertDialog(context, caseBloc.currentCase!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))); - } - - _getteams() { - List teams = []; - - caseBloc.currentCase!.teams!.forEach((_teams) { - String _teamsList; - _teamsList = _teams.name!; - teams.add(_teamsList); - }); - - return teams.toString().replaceAll("[", "").replaceAll("]", ""); - } - - _getUsers() { - List users = []; - - caseBloc.currentCase!.assignedTo!.forEach((_teams) { - String _teamsList; - _teamsList = _teams.firstName!; - users.add(_teamsList); - }); - - return users.toString().replaceAll("[", "").replaceAll("]", ""); - } - - void showDeleteAccountAlertDialog(BuildContext context, Case casee) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - casee.name != "" ? casee.name!.capitalizeFirstofEach() : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this account?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteCase(casee); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteCase(Case casee) async { - setState(() { - _isLoading = true; - }); - Map result = await caseBloc.deleteCase(casee); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - caseBloc.cases.clear(); - await caseBloc.fetchCases(); - await FirebaseAnalytics.instance.logEvent(name: "Case_deleted"); - Navigator.pushReplacementNamed(context, '/cases_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, 'Something went wrong', casee); - } - } - - showErrorMessage(BuildContext context, msg, Case casee) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteCase(casee); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/cases/cases_list.dart b/lib/ui/screens/cases/cases_list.dart deleted file mode 100644 index ded4ffc..0000000 --- a/lib/ui/screens/cases/cases_list.dart +++ /dev/null @@ -1,599 +0,0 @@ -import 'package:bottle_crm/bloc/case_bloc.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -//import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; - -class CasesList extends StatefulWidget { - CasesList(); - @override - State createState() => _CasesListState(); -} - -class _CasesListState extends State { - final GlobalKey _filtersFormKey = GlobalKey(); - bool _isLoading = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - bool _isFilter = false; - - List _cases = []; - Map _filtersFormData = { - "name": "", - "status": "", - "priority": "", - "account": "", - }; - - @override - void initState() { - setState(() { - _cases = caseBloc.cases; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - caseBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await caseBloc.fetchCases( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - caseBloc.offset = ""; - caseBloc.cases.clear(); - await caseBloc.fetchCases(filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['title'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter title", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['title'] = value; - }, - ), - ), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Status", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: caseBloc.statusObjForDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // caseBloc.currentEditCase["status"] = ""; - // } else { - // caseBloc.currentEditCase['status '] = - // selection; - // } - // }, - // selectedItem: - // caseBloc.currentEditCase['status '], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Status", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Source', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Priority", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: caseBloc.priorityObjForDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // caseBloc.currentEditCase['priority'] = - // ""; - // } else { - // caseBloc.currentEditCase['priority'] = - // selection; - // } - // }, - // selectedItem: - // caseBloc.currentEditCase['priority'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Priority", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Priority', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - SizedBox(height: 10.0), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "name": "", - "status": "", - "priority": "", - "account": "", - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - Widget _buildCasesList() { - return _cases.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _cases.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - caseBloc.currentCase = _cases[index]; - Navigator.pushNamed(context, '/case_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Text( - _cases[index].name!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - Container( - child: Text( - _cases[index].priority!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - ], - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - children: [ - _cases[index].createdBy!.profileUrl != - "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _cases[index].profileUrl!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context) - .primaryColor, - child: Text( - _cases[index].name![0], - style: TextStyle( - color: Colors.white, - fontWeight: - FontWeight.bold), - ), - ), - SizedBox(width: 3.0), - CircleAvatar( - radius: screenWidth / 25, - backgroundImage: NetworkImage( - "https://upload.wikimedia.org/wikipedia/commons/2/29/Ms._Smriti_Mandhana%2C_Arjun_Awardee_%28Cricket%29%2C_in_New_Delhi_on_July_16%2C_2019_%28cropped%29.jpg"), - ), - SizedBox(width: 3.0), - CircleAvatar( - radius: screenWidth / 25, - backgroundColor: Colors.grey, - child: Text( - "JR", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ) - ], - ), - ), - Row( - children: [ - Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: - ColorBrightness.light), - child: Text( - _cases[index].status!, - style: TextStyle( - color: Colors.white, - fontSize: 12.0), - ), - ), - ], - ), - ], - ), - ) - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Cases Found.'), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - Navigator.pop(context, true); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Cases', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, child: _buildCasesList()), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - caseBloc.currentEditCaseId = ""; - if (caseBloc.cases.length == 0) { - showAlertDialog(context); - } else { - Navigator.pushNamed(context, '/case_create'); - } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any cases, Please create case first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/case_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/contacts/contact_create.dart b/lib/ui/screens/contacts/contact_create.dart deleted file mode 100644 index 23ff8f2..0000000 --- a/lib/ui/screens/contacts/contact_create.dart +++ /dev/null @@ -1,1426 +0,0 @@ -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; -import 'dart:io'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter/services.dart'; -import 'package:intl/intl.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class CreateContact extends StatefulWidget { - CreateContact(); - @override - State createState() => _CreateContactState(); -} - -class _CreateContactState extends State { - var _currentTabIndex = 0; - quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _contactFormKey = GlobalKey(); - final GlobalKey _addressFormKey = GlobalKey(); - TextEditingController _dateController = TextEditingController(); - DateTime initialDate = DateTime.now(); - Map _errors = {}; - bool _isLoading = false; - String? selectedDate = ""; - File file = new File(''); - List _contactFormKeys = [ - "salutation", - "first_name", - "last_name", - "date_of_birth", - "organization", - "title", - "primary_email", - "mobile_number", - "secondary_number", - "department", - "language", - "do_not_call" - ]; - List _addressFormKeys = [ - "address_line ", - "street", - "city", - "state", - "pincode", - "country" - ]; - @override - void initState() { - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - super.initState(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - _selectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: DateTime(1950), - lastDate: DateTime.now(), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: buildContactBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 0; - }); - }, - child: buildAddressBlock()); - } else if (_currentTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: buildDescriptionBlock()); - } - } - - Positioned buildReqField() { - return Positioned( - child: Container( - width: 3.0, - color: Colors.red, - ), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildContactBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _contactFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Salutation ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['salutation'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - contactBloc.currentEditContact['salutation'] = - value; - }, - ), - ), - _errors['salutation'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['salutation'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'First Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['first_name'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - contactBloc.currentEditContact['first_name'] = - value; - }, - ), - ), - _errors['first_name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['first_name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Last Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - contactBloc.currentEditContact['last_name'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - contactBloc.currentEditContact['last_name'] = - value; - }, - ), - ), - _errors['last_name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['last_name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Phone Number", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['mobile_number'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - hintText: '+91 XXXXXXXXXX', - ), - keyboardType: TextInputType.phone, - onSaved: (value) { - contactBloc - .currentEditContact['mobile_number'] = - value; - }, - ), - ), - _errors['mobile_number'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['mobile_number'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Email ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['primary_email'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - if (value.isNotEmpty && - !RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(value)) { - return 'Enter valid email address.'; - } - return null; - }, - onSaved: (value) { - contactBloc - .currentEditContact['primary_email'] = - value; - }, - ), - ), - _errors['primary_email'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['primary_email'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Date of birth", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - // initialValue: contactBloc - // .currentEditContact['date_of_birth'], - controller: _dateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _selectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - keyboardType: TextInputType.text), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Organization", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['organization'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - contactBloc - .currentEditContact['organization'] = - value; - }, - ), - ), - _errors['organization'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['organization'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Title ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - contactBloc.currentEditContact['title'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - contactBloc.currentEditContact['title'] = - value; - }, - ), - ), - _errors['title'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['title'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Department", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['department'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - contactBloc - .currentEditContact['department'] = - value; - }), - ), - _errors['department'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['department'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Language", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['language'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - contactBloc.currentEditContact['language'] = - value; - }), - ), - _errors['language'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['language'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - child: Text( - "Do not call", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - ), - Container( - alignment: Alignment.centerRight, - child: Switch( - value: contactBloc - .currentEditContact['do_not_call'], - onChanged: (value) { - setState(() { - contactBloc.currentEditContact[ - 'do_not_call'] = value; - }); - }, - activeColor: Colors.blue, - focusColor: Colors.blue, - )), - ])), - ]))))); - } - - Widget buildAddressBlock() { - return SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _addressFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Address Line ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['address']['address_line'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - contactBloc.currentEditContact['address'] - ['address_line'] = value; - }, - ), - ), - _errors['address_line'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['address']['address_line'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Street ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['address']['street'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - // validator: (value) { - // if (value!.isEmpty) { - // return 'This field is required.'; - // } - // return null; - // }, - onSaved: (value) { - contactBloc.currentEditContact['address'] - ['street'] = value; - }, - ), - ), - _errors['street'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['address']['street'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'City ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['address']['city'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - // validator: (value) { - // if (value!.isEmpty) { - // return 'This field is required.'; - // } - // return null; - // }, - onSaved: (value) { - contactBloc.currentEditContact['address'] - ['city'] = value; - }, - ), - ), - _errors['city'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['address']['city'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'State ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['address']['state'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - // validator: (value) { - // if (value!.isEmpty) { - // return 'This field is required.'; - // } - // return null; - // }, - onSaved: (value) { - contactBloc.currentEditContact['address'] - ['state'] = value; - }, - ), - ), - _errors['state'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['address']['state'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Pincode ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: contactBloc - .currentEditContact['address']['pincode'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - // validator: (value) { - // if (value!.isEmpty) { - // return 'This field is required.'; - // } - // return null; - // }, - onSaved: (value) { - contactBloc.currentEditContact['address'] - ['pincode'] = value; - }, - ), - ), - _errors['pincode'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['address']['pincode'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Country ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.countries, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - contactBloc.currentEditContact['address'] - ['country'] = ""; - } else { - contactBloc.currentEditContact['address'] - ['country'] = selection; - } - }, - selectedItem: contactBloc - .currentEditContact['address']['country'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Counry", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - ])) - ])))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - quill.QuillSimpleToolbar( - controller: _controller, - config: const quill.QuillSimpleToolbarConfig(), - ), - Expanded( - child: Container( - child: quill.QuillEditor.basic( - controller: _controller, - config: const quill.QuillEditorConfig()), - ), - ) - ], - )); - } - - @override - Widget build(BuildContext context) { - // Set readOnly property based on loading state - _controller.readOnly = _isLoading; - - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - contactBloc.cancelCurrentEditContact(); - contactBloc.currentEditContactId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - contactBloc.currentEditContactId == "" - ? 'Add Contact' - : "Edit Contact", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - // contactBloc.currentEditContact['description'] = - // _controller.document.toPlainText(); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Contact', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Address', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_contactFormKey.currentState != null) { - if (!_contactFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _contactFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_addressFormKey.currentState != null) { - if (!_addressFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _addressFormKey.currentState!.save(); - Map _result = {}; - if (contactBloc.currentEditContactId != null && - contactBloc.currentEditContactId != "") { - _result = await contactBloc.editContact(); - } else { - _result = await contactBloc.createContact(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - contactBloc.cancelCurrentEditContact(); - contactBloc.currentEditContactId = ""; - showToaster(_result['message'], context); - contactBloc.contacts.clear(); - contactBloc.offset = ""; - await contactBloc.fetchContacts(); - await FirebaseAnalytics.instance.logEvent(name: "Contact_Created"); - Navigator.pushReplacementNamed(context, '/contacts_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']['contact_errors']; - }); - for (var key in _contactFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - for (var key in _addressFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 1; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - // showErrorMessage(context, _result['message'].toString()); - } - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/contacts/contact_details.dart b/lib/ui/screens/contacts/contact_details.dart deleted file mode 100644 index d375ae5..0000000 --- a/lib/ui/screens/contacts/contact_details.dart +++ /dev/null @@ -1,739 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class ContactDetails extends StatefulWidget { - ContactDetails(); - @override - State createState() => _ContactDetailsState(); -} - -class _ContactDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - if (_currentTabIndex == 0) { - setState(() { - _currentTabIndex = 1; - }); - } - }, - child: buildContactInfoBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - child: buildSocialBlock()); - } else if (_currentTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildDescriptionBlock()); - } - } - - buildSocialBlock() { - return Container( - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - color: Colors.white, - child: Text("No Socials Found..."), - ); - } - - buildDescriptionBlock() { - return Container( - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - color: Colors.white, - child: Text( - contactBloc.currentContact!.description != "" - ? contactBloc.currentContact!.description! - : "No Description Found", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22.0)), - ); - } - - buildContactInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "First Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - contactBloc.currentContact!.firstName! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Second Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - contactBloc.currentContact!.lastName! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Title :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - contactBloc.currentContact!.title! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Crated Date :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - contactBloc.currentContact!.createdOn! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - )), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Text( - "http://www.micropyramid.com", - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 30), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - contactBloc.currentContact!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${contactBloc.currentContact!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: - Icon(Icons.email_outlined, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - contactBloc.currentContact!.primaryEmail!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Text( - contactBloc.currentContact!.secondaryEmail! != "" - ? contactBloc.currentContact!.secondaryEmail! - : "-----", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - contactBloc.currentContact!.primaryMobile != "" - ? contactBloc.currentContact!.primaryMobile! - : "-----", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Text( - " +91 0000 000 000", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Do not call :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - alignment: Alignment.centerLeft, - width: screenWidth * 0.50, - child: Switch( - value: contactBloc.currentContact!.doNotCall!, - onChanged: (value) {}, - activeColor: Colors.blue, - focusColor: Colors.blue, - )) - ], - ), - ], - ), - ), - SizedBox(height: 10), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column(children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Address :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "${contactBloc.currentContact!.address!['address_line']}${contactBloc.currentContact!.address!['street']}${contactBloc.currentContact!.address!['city']}${contactBloc.currentContact!.address!['state']}${contactBloc.currentContact!.address!['postcode']}${contactBloc.currentContact!.address!['country']}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ])), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteContactAlertDialog( - context, contactBloc.currentContact!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Contact Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.edit_outlined, - size: screenWidth / 18, - color: Theme.of(context).primaryColor), - GestureDetector( - onTap: () async { - if (!_isLoading) { - contactBloc.currentEditContactId = - contactBloc.currentContact!.id.toString(); - await contactBloc.updateCurrentEditContact( - contactBloc.currentContact!); - Navigator.pushNamed( - context, '/contact_create'); - } - }, - child: Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ) - ], - ), - ), - !_isLoading - ? Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Contact Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Social', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.21, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: !_isLoading - ? Container( - child: buildTopBar(), - color: Colors.white, - ) - : Container(color: Colors.white)) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - ); - } - - void showDeleteContactAlertDialog(BuildContext context, Contact contact) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - contact.firstName != "" - ? contact.firstName!.capitalizeFirstofEach() - : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this contact?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteContact(contact); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteContact(Contact contact) async { - setState(() { - _isLoading = true; - }); - Map result = await contactBloc.deleteContact(contact); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - contactBloc.contacts.clear(); - await contactBloc.fetchContacts(); - await FirebaseAnalytics.instance.logEvent(name: "Contact_Deleted"); - Navigator.pushReplacementNamed(context, '/contacts_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, 'Something went wrong', contact); - } - } - - showErrorMessage(BuildContext context, msg, Contact contact) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteContact(contact); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/contacts/contacts_list.dart b/lib/ui/screens/contacts/contacts_list.dart deleted file mode 100644 index ea749d5..0000000 --- a/lib/ui/screens/contacts/contacts_list.dart +++ /dev/null @@ -1,488 +0,0 @@ -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; - -class ContactsList extends StatefulWidget { - ContactsList(); - @override - State createState() => _ContactsListState(); -} - -class _ContactsListState extends State { - final GlobalKey _filtersFormKey = GlobalKey(); - bool _isFilter = false; - List _contacts = []; - Map _filtersFormData = {"name": "", "city": "", "assigned_to": []}; - bool _isLoading = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - - @override - void initState() { - setState(() { - _contacts = contactBloc.contacts; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - contactBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await contactBloc.fetchContacts( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - contactBloc.contacts.clear(); - await contactBloc.fetchContacts( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter Name", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['name'] = value; - }, - ), - ), - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['city'], - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter City", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['city'] = value; - }, - ), - ), - SizedBox(height: 10.0), - Container( - padding: padding(), - child: Container( - width: screenWidth * 0.92, - child: Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.assignedToList, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Users", - ), - initialValue: _filtersFormData['assigned_to'], - onSaved: (value) { - if (value == null) return; - _filtersFormData['assigned_to'] = value; - }, - ), - ), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "name": "", - "city": "", - "assigned_to": [] - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - Widget _buildContactsList() { - return _contacts.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _contacts.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - contactBloc.currentContact = _contacts[index]; - Navigator.pushNamed(context, '/contact_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.6, - child: Text( - _contacts[index] - .firstName! - .capitalizeFirstofEach() + - " " + - _contacts[index].lastName!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - Container( - child: Text( - _contacts[index].createdOn!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ) - ], - ), - SizedBox(height: 8.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.4, - child: Row( - children: [ - Icon( - Icons.phone, - color: Colors.green, - size: screenWidth / 20, - ), - SizedBox(width: 5.0), - Container( - child: Text( - _contacts[index].primaryMobile == "" - ? "---------" - : _contacts[index] - .primaryMobile!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 25), - ), - ) - ], - ), - ), - Container( - width: screenWidth * 0.4, - child: Row( - children: [ - Container( - child: Icon( - Icons.email_outlined, - color: Colors.blue, - size: screenWidth / 20, - )), - SizedBox(width: 5.0), - Container( - width: screenWidth * 0.33, - child: Text( - _contacts[index].primaryEmail == - "" - ? "--------" - : _contacts[index] - .primaryEmail!, - style: TextStyle( - overflow: - TextOverflow.ellipsis, - color: Colors.grey, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w600)), - ) - ], - ), - ), - ], - ), - ) - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Contacts Found.'), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - currentBottomNavigationIndex == "4" - ? Navigator.pushReplacementNamed( - context, "/dashboard") - : Navigator.pushReplacementNamed( - context, "/more_options"); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Contacts', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, - child: _buildContactsList(), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.pushNamed(context, '/contact_create'); - contactBloc.currentEditContactId = ""; - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any contacts, Please create contact first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/contacts_list"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/dashboard/dashboard.dart b/lib/ui/screens/dashboard/dashboard.dart deleted file mode 100644 index 7ac64b7..0000000 --- a/lib/ui/screens/dashboard/dashboard.dart +++ /dev/null @@ -1,403 +0,0 @@ -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/ui/widgets/recent_card_widget.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/ui/widgets/dashboard_count_card.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class Dashboard extends StatefulWidget { - Dashboard(); - @override - State createState() => _DashboardState(); -} - -class _DashboardState extends State { - int _selectedTabIndex = 0; - - @override - void initState() { - super.initState(); - } - - OutlineInputBorder boxBorder(Color color) { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(0)), - borderSide: BorderSide(width: 0, color: color), - ); - } - - Widget _buildCards(BuildContext context) { - return Container( - padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0), - child: Column( - children: [ - Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CountCard( - //color: Color.fromRGBO(44, 113, 255, 1), - color: Colors.white, - lable: "Accounts", - count: dashboardBloc.dashboardData['accountsCount'], - icon: 'assets/images/accounts_color.svg', - routeName: "/accounts_list", - index: 1), - CountCard( - //color: Color.fromRGBO(96, 75, 186, 1), - color: Colors.white, - lable: "Leads", - count: dashboardBloc.dashboardData['leadsCount'], - icon: 'assets/images/flag.svg', - routeName: "/leads_list", - index: 4) - ], - ), - ), - Container( - margin: EdgeInsets.only(top: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CountCard( - //color: Color.fromRGBO(52, 141, 80, 1), - color: Colors.white, - lable: "Contacts", - count: dashboardBloc.dashboardData['contactsCount'], - icon: 'assets/images/identification.svg', - routeName: "/contacts_list", - index: 4), - CountCard( - //color: Color.fromRGBO(255, 86, 45, 1), - color: Colors.white, - lable: "Opportunities", - count: dashboardBloc.dashboardData['opportunitiesCount'], - icon: 'assets/images/opportunities_color.svg', - routeName: "/opportunities_list", - index: 4) - ], - ), - ), - ], - ), - ); - } - - Widget _buildRecentAccounts(BuildContext context) { - return dashboardBloc.dashboardData['accounts'] != null && - dashboardBloc.dashboardData['accounts'].length > 0 - ? ListView.builder( - itemCount: dashboardBloc.dashboardData['accounts'].length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () {}, - child: RecentCardWidget( - source: 'accounts', - name: dashboardBloc.dashboardData['accounts'][index].name, - photoUrl: dashboardBloc.dashboardData['accounts'][index] - .createdBy!.profileUrl == - null - ? dashboardBloc.dashboardData['accounts'][index] - .createdBy!.firstName[0].allInCaps - : dashboardBloc.dashboardData['accounts'][index] - .createdBy!.profileUrl, - createdBy: dashboardBloc - .dashboardData['accounts'][index].createdBy!.firstName, - tags: dashboardBloc.dashboardData['accounts'][index].tags!, - date: - dashboardBloc.dashboardData['accounts'][index].createdOn, - city: dashboardBloc - .dashboardData['accounts'][index].billingCity, - email: dashboardBloc.dashboardData['accounts'][index].email, - ), - ); - }) - : Container( - margin: EdgeInsets.only(top: 10.0), - child: Text("No Data Found", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).secondaryHeaderColor)), - ); - } - - Widget _buildRecentContacts(BuildContext context) { - return dashboardBloc.dashboardData['contacts'] != null && - dashboardBloc.dashboardData['contacts'].length > 0 - ? ListView.builder( - itemCount: dashboardBloc.dashboardData['contacts'].length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () {}, - child: RecentCardWidget( - source: 'contacts', - name: dashboardBloc - .dashboardData['contacts'][index].firstName + - "" + - dashboardBloc.dashboardData['contacts'][index].lastName, - date: - dashboardBloc.dashboardData['contacts'][index].createdOn, - tags: [], - photoUrl: dashboardBloc - .dashboardData['contacts'][index].createdBy!.profileUrl, - createdBy: dashboardBloc - .dashboardData['contacts'][index].createdBy!.firstName, - email: dashboardBloc - .dashboardData['contacts'][index].primaryEmail, - ), - ); - }) - : Container( - margin: EdgeInsets.only(top: 10.0), - child: Text("No Data Found", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).secondaryHeaderColor)), - ); - } - - Widget _buildRecentOpportunities(BuildContext context) { - return dashboardBloc.dashboardData['opportunities'] != null && - dashboardBloc.dashboardData['opportunities'].length > 0 - ? ListView.builder( - itemCount: dashboardBloc.dashboardData['opportunities'].length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () {}, - child: RecentCardWidget( - source: 'opportunities', - name: - dashboardBloc.dashboardData['opportunities'][index].name, - photoUrl: dashboardBloc.dashboardData['opportunities'][index] - .createdBy!.profileUrl, - createdBy: dashboardBloc.dashboardData['opportunities'][index] - .createdBy!.firstName, - tags: - dashboardBloc.dashboardData['opportunities'][index].tags!, - date: dashboardBloc - .dashboardData['opportunities'][index].createdOn, - city: dashboardBloc - .dashboardData['opportunities'][index].leadSource, - email: dashboardBloc - .dashboardData['opportunities'][index].amount, - ), - ); - }) - : Container( - margin: EdgeInsets.only(top: 10.0), - child: Text("No Data Found", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).secondaryHeaderColor)), - ); - } - - Widget _recentTabWidget() { - return Column( - children: [ - Container( - margin: EdgeInsets.only(bottom: 10.0, left: 10.0), - alignment: Alignment.centerLeft, - child: Text( - "Recently added", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: screenWidth / 25, - ), - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: Color.fromARGB(5, 250, 250, 251), - borderRadius: BorderRadius.all(Radius.circular(20.0)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _selectedTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: bottomNavBarSelectedTextColor, - width: _selectedTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Accounts ', - style: TextStyle( - color: _selectedTabIndex == 0 - ? bottomNavBarSelectedTextColor - : Colors.grey, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _selectedTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: bottomNavBarSelectedTextColor, - width: _selectedTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Contacts ', - style: TextStyle( - color: _selectedTabIndex == 1 - ? bottomNavBarSelectedTextColor - : Colors.grey, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _selectedTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: bottomNavBarSelectedTextColor, - width: _selectedTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.30, - child: Text( - 'Opportunities ', - style: TextStyle( - color: _selectedTabIndex == 2 - ? bottomNavBarSelectedTextColor - : Colors.grey, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ); - } - - _buildtabSelectTab() { - if (_selectedTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _selectedTabIndex = 1; - }); - }, - child: _buildRecentAccounts(context)); - } else if (_selectedTabIndex == 1) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _selectedTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - _selectedTabIndex = 0; - }); - }, - child: _buildRecentContacts(context)); - } else if (_selectedTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _selectedTabIndex = 1; - }); - }, - child: _buildRecentOpportunities(context)); - } - } - - @override - Widget build(BuildContext context) { - WidgetsFlutterBinding.ensureInitialized(); - SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); - return PopScope( - canPop: false, - onPopInvokedWithResult: (didPop, result) { - if (!didPop) { - Navigator.pushNamedAndRemoveUntil( - context, '/companies_List', (route) => false); - } - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric( - horizontal: 20.0, vertical: 10.0), - child: Text( - 'Dashboard', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ), - Expanded( - child: Container( - color: Colors.white, - child: Column( - children: [ - _buildCards(context), - _recentTabWidget(), - Expanded( - child: _buildtabSelectTab(), - ), - ], - ), - ), - ), - ], - ), - ), - ), - ]), - bottomNavigationBar: BottomNavigationBarWidget())); - } -} diff --git a/lib/ui/screens/documents/document_create.dart b/lib/ui/screens/documents/document_create.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/ui/screens/documents/document_details.dart b/lib/ui/screens/documents/document_details.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/ui/screens/documents/documents_list.dart b/lib/ui/screens/documents/documents_list.dart deleted file mode 100644 index 417b66e..0000000 --- a/lib/ui/screens/documents/documents_list.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; - -class DocumentsList extends StatefulWidget { - DocumentsList(); - @override - State createState() => _DocumentsListState(); -} - -class _DocumentsListState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Documents List'), - ), - body: Center( - child: Text('No Documents Found'), - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } -} diff --git a/lib/ui/screens/events/event_create.dart b/lib/ui/screens/events/event_create.dart deleted file mode 100644 index ec64f54..0000000 --- a/lib/ui/screens/events/event_create.dart +++ /dev/null @@ -1,994 +0,0 @@ -import 'dart:io'; -import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/bloc/event_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; - -class CreateEvent extends StatefulWidget { - CreateEvent(); - @override - State createState() => _CreateEventState(); -} - -class _CreateEventState extends State { - quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _eventFormKey = GlobalKey(); - TextEditingController _startDateController = TextEditingController(); - TextEditingController _endDateController = TextEditingController(); - TextEditingController _startTimeController = TextEditingController(); - TextEditingController _endTimeController = TextEditingController(); - TextEditingController fileNameController = new TextEditingController(); - String? selectedDate = ""; - DateTime? initialDate = DateTime.now(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File file = new File(''); - List _eventFormKeys = [ - "name", - "event_type", - "contacts", - "start_date", - "start_time", - "end_date", - "end_time", - "description", - "teams", - "assigned_to", - "recurring_day", - ]; - - TimeOfDay startSelectedTime = TimeOfDay.now(); - TimeOfDay endSelectedTime = TimeOfDay.now(); - - @override - void initState() { - _startDateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - _endDateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - - _startTimeController.text = "00:00:00"; - _endTimeController.text = "00:00:00"; - super.initState(); - } - - _StartSelectDate(BuildContext context) async { - showTimePicker(context: context, initialTime: TimeOfDay.now()); - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate!, - firstDate: DateTime(1965), - lastDate: DateTime.now().add(Duration(days: 730)), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _startDateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - _endSelectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate!, - firstDate: DateTime(1965), - lastDate: DateTime.now().add(Duration(days: 730)), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _endDateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_eventFormKey.currentState != null) - _eventFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: _buildEventBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildDescriptionBlock()); - } - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget _buildEventBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _eventFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Event Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - eventBloc.currentEditEvent['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - eventBloc.currentEditEvent['name'] = value; - }, - ), - ), - _errors['name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Event Type ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownButtonFormField( - decoration: InputDecoration( - border: boxBorder(), - contentPadding: EdgeInsets.all(12.0)), - style: TextStyle(color: Colors.black), - hint: Text('select Event Type'), - value: eventBloc.currentEditEvent['event_type'], - onChanged: (value) { - accountBloc.currentEditAccount['event_type'] = - value; - }, - items: - ['Recurring', 'Non-Recurring'].map((item) { - return DropdownMenuItem( - child: new Text(item), - value: item, - ); - }).toList(), - ), - ), - _errors['event_type'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['event_type'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Contacts ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: - eventBloc.currentEditEvent['contacts'], - onSaved: (value) { - if (value == null) return; - eventBloc.currentEditEvent['contacts'] = - value; - }, - ), - ), - _errors['event_type'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['event_type'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Start Date ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _startDateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _StartSelectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - print(value); - eventBloc.currentEditEvent['start_date'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Start Time ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _startTimeController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () async { - final TimeOfDay? picked_s = - await showTimePicker( - context: context, - initialTime: startSelectedTime, - builder: (BuildContext? context, - Widget? child) { - return MediaQuery( - data: MediaQuery.of(context!) - .copyWith( - alwaysUse24HourFormat: - true), - child: child!, - ); - }); - - if (picked_s != null && - picked_s != startSelectedTime) - setState(() { - startSelectedTime = picked_s; - DateTime parsedTime = DateFormat.jm() - .parse(picked_s - .format(context) - .toString()); - _startTimeController.text = - DateFormat('HH:mm:ss') - .format(parsedTime); - }); - }, - icon: Icon(Icons.punch_clock_outlined), - ), - ), - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - print(value); - eventBloc.currentEditEvent['start_time'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "End Date ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _endDateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _endSelectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - // keyboardType: TextInputType.text - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - print(value); - eventBloc.currentEditEvent['end_date'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "End Time ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _endTimeController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () async { - final TimeOfDay? picked_s = - await showTimePicker( - context: context, - initialTime: endSelectedTime, - builder: (BuildContext? context, - Widget? child) { - return MediaQuery( - data: MediaQuery.of(context!) - .copyWith( - alwaysUse24HourFormat: - true), - child: child!, - ); - }); - - if (picked_s != null && - picked_s != endSelectedTime) - setState(() { - endSelectedTime = picked_s; - DateTime parsedTime = DateFormat.jm() - .parse(picked_s - .format(context) - .toString()); - _endTimeController.text = - DateFormat('HH:mm:ss') - .format(parsedTime); - }); - }, - icon: Icon(Icons.punch_clock) - ), - ), - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - eventBloc.currentEditEvent['end_time'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: - eventBloc.currentEditEvent['teams'], - onSaved: (value) { - if (value == null) return; - eventBloc.currentEditEvent['teams'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned to", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Users", - ), - initialValue: eventBloc - .currentEditEvent['assigned_to'], - onSaved: (value) { - if (value == null) return; - eventBloc - .currentEditEvent['assigned_to'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Recurring Days", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: eventBloc.recurringDays, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Recurring Days", - ), - initialValue: eventBloc - .currentEditEvent['recurring_days'], - onSaved: (value) { - if (value == null) return; - eventBloc.currentEditEvent[ - 'recurring_days'] = value; - })) - ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - quill.QuillSimpleToolbar( - controller: _controller, - config: const quill.QuillSimpleToolbarConfig(), - ), - Expanded( - child: Container( - child: quill.QuillEditor.basic( - controller: _controller, - config: const quill.QuillEditorConfig()), - ), - ) - ], - )); - } - - @override - Widget build(BuildContext context) { - // Set readOnly property based on loading state - _controller.readOnly = _isLoading; - - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - dashboardBloc.fetchDashboardDetails(); - eventBloc.cancelCurrentEditEvent(); - eventBloc.currentEditEventId = ""; - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - eventBloc.currentEditEventId == "" - ? 'Add Event' - : "Edit Event", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_eventFormKey.currentState != null) - _eventFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - eventBloc.currentEditEvent['description'] = - _controller.document.toPlainText(); - print(eventBloc.currentEditEvent['description']); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Event', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_eventFormKey.currentState != null) - _eventFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container(color: Colors.white, child: _buildEventBlock()), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_eventFormKey.currentState != null) { - if (!_eventFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _eventFormKey.currentState!.save(); - await Future.delayed(const Duration(seconds: 1), () async {}); - - Map _result = {}; - if (eventBloc.currentEditEventId != null && - eventBloc.currentEditEventId != "") { - _result = await eventBloc.editEvent(); - } else { - _result = await eventBloc.createEvent(); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - eventBloc.cancelCurrentEditEvent(); - eventBloc.currentEditEventId = ""; - showToaster(_result['message'], context); - eventBloc.events.clear(); - eventBloc.offset = ""; - await eventBloc.fetchEvents(); - eventBloc.events; - await FirebaseAnalytics.instance.logEvent(name: "Event_Created"); - Navigator.pushReplacementNamed(context, '/events_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _eventFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/events/event_details.dart b/lib/ui/screens/events/event_details.dart deleted file mode 100644 index 8d6a45a..0000000 --- a/lib/ui/screens/events/event_details.dart +++ /dev/null @@ -1,614 +0,0 @@ -import 'package:bottle_crm/bloc/event_bloc.dart'; -import 'package:bottle_crm/model/events.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:intl/intl.dart'; - -class EventDetails extends StatefulWidget { - EventDetails(); - @override - State createState() => _EventDeailsState(); -} - -class _EventDeailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Event Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - eventBloc.currentEditEventId = - eventBloc.currentEvent!.id.toString(); - await eventBloc - .updateCurrentEditEvent(eventBloc.currentEvent!); - Navigator.pushNamed(context, '/event_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Event Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - child: buildTaskInfoBlock(), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildTaskInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - eventBloc.currentEvent!.name!.capitalizeFirstofEach(), - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - padding: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: ColorBrightness.light), - child: Text( - eventBloc.currentEvent!.status!, - style: TextStyle(color: Colors.white, fontSize: 12.0), - ), - ), - SizedBox(height: 5.0), - Container( - child: Container( - child: Row( - children: [ - Container( - child: ProfilePicViewWidget(eventBloc - .currentEvent!.assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser.firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - ], - ), - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Event Type :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - eventBloc.currentEvent!.eventType!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - // Row( - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: Text( - // "Create Date :", - // style: TextStyle( - // color: Colors.blueGrey[800], - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Text( - // eventBloc.currentEvent!.createdOn!, - // style: TextStyle( - // color: Colors.black45, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // ], - // ), - // SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Start :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - eventBloc.currentEvent!.startDate! == "" - ? "-----" - : DateFormat("dd-MM-yyyy").format( - DateTime.parse( - eventBloc.currentEvent!.startDate!))+" "+eventBloc.currentEvent!.startTime!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "End :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - eventBloc.currentEvent!.startDate! == "" - ? "-----" - : DateFormat("dd-MM-yyyy").format( - DateTime.parse( - eventBloc.currentEvent!.startDate!))+" "+eventBloc.currentEvent!.endTime!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - ], - )), - SizedBox(height: 10.0), - Container( - // padding: EdgeInsets.all(10.0), - // decoration: BoxDecoration( - // border: Border.all(width: 1.0, color: Colors.black12), - // borderRadius: BorderRadius.all(Radius.circular(5.0)), - // ), - // child: Column( - // children: [ - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: Text( - // "Organization :", - // style: TextStyle( - // color: Colors.blueGrey[800], - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Column( - // mainAxisAlignment: MainAxisAlignment.start, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // authBloc.selectedOrganization!.name! - // .capitalizeFirstofEach(), - // style: TextStyle( - // color: Colors.black45, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // ), - // ], - // )), - // ], - // ), - // SizedBox(height: 10), - // Row( - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: Text( - // "Contact :", - // style: TextStyle( - // color: Colors.blueGrey[800], - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Text( - // taskBloc.currentTask!.createdBy!.firstName! - // .capitalizeFirstofEach() + - // " ${taskBloc.currentTask!.createdBy!.lastName!}", - // style: TextStyle( - // color: Colors.black45, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // ], - // ), - // SizedBox(height: 10), - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: - // Icon(Icons.email_outlined, size: screenWidth / 20)), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Column( - // mainAxisAlignment: MainAxisAlignment.start, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "account@mp.com", - // style: TextStyle( - // color: Colors.black45, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // ), - // Container( - // padding: EdgeInsets.symmetric(vertical: 5.0), - // child: Divider()) - // ], - // )), - // ], - // ), - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: Icon(Icons.phone, size: screenWidth / 20)), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Column( - // mainAxisAlignment: MainAxisAlignment.start, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "------------", - // style: TextStyle( - // color: Colors.black45, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // ), - // Container( - // padding: EdgeInsets.symmetric(vertical: 5.0), - // child: Divider()) - // ], - // )), - // ], - // ), - // Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // alignment: Alignment.centerRight, - // width: screenWidth * 0.28, - // child: Text( - // "Priority :", - // style: TextStyle( - // color: Colors.blueGrey[800], - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Text( - // taskBloc.currentTask!.priority == "" - // ? "------" - // : taskBloc.currentTask!.priority!, - // style: TextStyle( - // color: taskBloc.currentTask!.priority == "" - // ? Colors.black45 - // : Colors.blue, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - // ], - // ), - // ], - // ), - ), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteTaskAlertDialog(context, eventBloc.currentEvent!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))); - } - - void showDeleteTaskAlertDialog(BuildContext context, Event event) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - event.name != "" ? event.name!.capitalizeFirstofEach() : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this Event?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteEvent(event); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteEvent(Event event) async { - setState(() { - _isLoading = true; - }); - Map result = await eventBloc.deleteEvent(event); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - eventBloc.events.clear(); - await eventBloc.fetchEvents(); - await FirebaseAnalytics.instance.logEvent(name: "Event_Deleted"); - Navigator.pushReplacementNamed(context, '/events_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, result['message'].toString(), event); - } - } - - showErrorMessage(BuildContext context, msg, Event event) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteEvent(event); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/events/events_list.dart b/lib/ui/screens/events/events_list.dart deleted file mode 100644 index c4a4372..0000000 --- a/lib/ui/screens/events/events_list.dart +++ /dev/null @@ -1,221 +0,0 @@ -import 'package:bottle_crm/bloc/event_bloc.dart'; -import 'package:bottle_crm/model/events.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:intl/intl.dart'; - -class EventsList extends StatefulWidget { - EventsList(); - @override - State createState() => _EventsListState(); -} - -class _EventsListState extends State { - List _events = []; - bool _isLoading = false; - bool _isFilter = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - - @override - void initState() { - setState(() { - _events = eventBloc.events; - }); - super.initState(); - } - - Widget _buildTasksList() { - return _events.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _events.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - eventBloc.currentEvent = _events[index]; - Navigator.pushNamed(context, '/event_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _events[index] - .name! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Text(DateFormat("dd-MM-yyyy").format(DateTime.parse(_events[index].dateOfMeeting!)), - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - //crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - _events[index].startDate!+" "+_events[index].startTime! , - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - Text( - "To" , - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 22)), - Text( - _events[index].endDate!+" "+_events[index].endTime! , - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ) - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Accounts Found.'), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - Navigator.pushReplacementNamed( - context, "/more_options"); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Events', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Expanded( - child: Container( - color: Colors.white, - child: _buildTasksList(), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - // accountBloc.currentEditAccountId = ""; - // if (accountBloc.openAccounts.length == 0) { - // showAlertDialog(context); - // } else { - Navigator.pushNamed(context, '/event_create'); - // } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } -} diff --git a/lib/ui/screens/http_excepion.dart b/lib/ui/screens/http_excepion.dart deleted file mode 100644 index 43518df..0000000 --- a/lib/ui/screens/http_excepion.dart +++ /dev/null @@ -1,10 +0,0 @@ -class HttpException implements Exception { - final String errorMessage; - - HttpException(this.errorMessage); - - @override - String toString() { - return errorMessage; - } -} diff --git a/lib/ui/screens/invoices/invoice_create.dart b/lib/ui/screens/invoices/invoice_create.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/ui/screens/invoices/invoice_details.dart b/lib/ui/screens/invoices/invoice_details.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/ui/screens/invoices/invoices_list.dart b/lib/ui/screens/invoices/invoices_list.dart deleted file mode 100644 index dcc1d2a..0000000 --- a/lib/ui/screens/invoices/invoices_list.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; - -class InvoicesList extends StatefulWidget { - InvoicesList(); - @override - State createState() => _InvoicesListState(); -} - -class _InvoicesListState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Invoices List'), - ), - body: Center( - child: Text('NO Invoice Found'), - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } -} diff --git a/lib/ui/screens/leads/lead_create.dart b/lib/ui/screens/leads/lead_create.dart deleted file mode 100644 index ccd810c..0000000 --- a/lib/ui/screens/leads/lead_create.dart +++ /dev/null @@ -1,1715 +0,0 @@ -import 'dart:io'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -//import 'package:textfield_tags/textfield_tags.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; - -class CreateLead extends StatefulWidget { - CreateLead(); - @override - State createState() => _CreateLeadState(); -} - -class _CreateLeadState extends State { - var _currentTabIndex = 0; - quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _leadFormKey = GlobalKey(); - final GlobalKey _contactFormKey = GlobalKey(); - final GlobalKey _addressFormKey = GlobalKey(); - TextEditingController fileNameController = new TextEditingController(); - File? file = File(''); - Map _errors = {}; - bool _isLoading = false; - - List _leadFormKeys = [ - "title", - "account_name", - "website ", - "assigned_to", - "organization", - "status", - "source", - "tags", - "skype_ID", - "opportunity_amount", - "industry" - ]; - - List _contactFormKeys = [ - "first_name", - "last_name", - "email", - "phone", - ]; - - List _addressFormKeys = [ - "address_line", - "street", - "city", - "state", - "postcode", - "country", - ]; - - @override - void initState() { - super.initState(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildLeadBlock(); - } else if (_currentTabIndex == 1) { - return buildContactBlock(); - } else if (_currentTabIndex == 2) { - return buildAddressBlock(); - } else if (_currentTabIndex == 3) { - return buildDescriptionBlock(); - } - } - - Positioned buildReqField() { - return Positioned( - child: Container( - width: 3.0, - color: Colors.red, - ), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - _filePicker() async { - FilePickerResult? result = - await FilePicker.platform.pickFiles(allowMultiple: false); - if (result != null) { - file = File(result.files[0].path!); - var _filename = file!.path.toString(); - var split = _filename.split('/'); - Map values = { - for (int i = 0; i < split.length; i++) i: split[i] - }; - setState(() { - fileNameController.text = values[7].toString(); - }); - } else {} - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildLeadBlock() { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_leadFormKey.currentState != null) - _leadFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _leadFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Lead Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['title'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['title'] = value; - }, - ), - ), - _errors['title'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['title'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Website ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['website'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - hintText: 'https://www.bottlecrm.com', - enabledBorder: - buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: - buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - leadBloc.currentEditLead['website'] = - value; - }, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }), - ), - _errors['website'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['website'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Assigned To ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - // validator: (value) { - // if (value == null) { - // return 'Please select one or more options'; - // } - // return null; - // }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Users", - ), - initialValue: - leadBloc.currentEditLead['assigned_to'], - onSaved: (value) { - if (value == null) return; - leadBloc.currentEditLead['assigned_to'] = - value; - }, - ), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Status ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - height: screenHeight / 17, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.status, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - leadBloc.currentEditLead['status'] = ""; - } else { - leadBloc.currentEditLead['status'] = - selection; - } - }, - selectedItem: - leadBloc.currentEditLead['status'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Status", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Source ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - height: screenHeight / 17, - child: Stack(children: [ - DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.source, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - leadBloc.currentEditLead['source'] = - ""; - } else { - leadBloc.currentEditLead['source'] = - selection; - } - }, - selectedItem: - leadBloc.currentEditLead['source'], - popupProps: PopupProps.bottomSheet( - itemBuilder: - (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, - vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: - screenWidth / 22)), - ); - }, - constraints: - BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Source", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ])), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Amount ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: leadBloc - .currentEditLead['opportunity_amount'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - onSaved: (value) { - leadBloc.currentEditLead[ - 'opportunity_amount'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'SkypeID ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['skype_ID'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - leadBloc.currentEditLead['skype_ID'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Attachment ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: fileNameController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: - buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: - buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: _filePicker, - icon: Icon(Icons.upload))), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'Industry ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - height: screenHeight / 17, - child: Stack(children: [ - DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.industry, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - leadBloc.currentEditLead['industry'] = - ""; - } else { - leadBloc.currentEditLead['industry'] = - selection; - } - }, - selectedItem: - leadBloc.currentEditLead['industry'], - popupProps: PopupProps.bottomSheet( - itemBuilder: - (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, - vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: - screenWidth / 22)), - ); - }, - constraints: - BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Industry", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ])), - ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // width: screenWidth * 0.92, - // child: RichText( - // text: TextSpan( - // text: 'Tags ', - // style: buildLableTextStyle(), - // ), - // )), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 9, - // child: Container( - // margin: EdgeInsets.only(bottom: 5.0), - // child: TextFieldTags( - // initialTags: - // leadBloc.currentEditLead['tags'], - // textFieldStyler: TextFieldStyler( - // //contentPadding: EdgeInsets.all(12.0), - // textFieldBorder: - // buildBorder(Colors.black54), - // textFieldFocusedBorder: - // buildBorder(Colors.black54), - // hintText: 'Enter Tags', - // hintStyle: TextStyle(fontSize: 16.0), - // helperText: "", - // ), - // tagsStyler: TagsStyler( - // tagTextPadding: EdgeInsets.symmetric( - // horizontal: 5.0), - // tagDecoration: BoxDecoration( - // color: Colors.lightGreen[300], - // borderRadius: - // BorderRadius.circular(0.0), - // ), - // tagCancelIcon: Icon(Icons.cancel, - // size: 18.0, - // color: Colors.green[900]), - // tagPadding: const EdgeInsets.all(6.0)), - // onTag: (tag) { - // setState(() { - // leadBloc.currentEditLead['tags'] - // .add(tag); - // }); - // }, - // onDelete: (tag) { - // setState(() { - // leadBloc.currentEditLead['tags'] - // .remove(tag); - // }); - // }, - // ), - // ), - // ), - // ])), - ]))))), - ); - } - - Widget buildContactBlock() { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - _currentTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - _currentTabIndex = 0; - }); - }, - child: Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _contactFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - width: screenWidth * 0.92, - child: RichText( - text: TextSpan( - text: 'First Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['first_name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['first_name'] = - value; - }, - ), - ), - _errors['first_name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['first_name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Last Name ', - style: buildLableTextStyle(), - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - height: screenHeight / 17, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['last_name'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - leadBloc.currentEditLead['last_name'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Email Address ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['email'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - if (value.isNotEmpty && - !RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(value)) { - return 'Enter valid email address.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['email'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Phone Number ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['phone'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - hintText: '+91 XXXXXXXXXX', - ), - keyboardType: TextInputType.phone, - onSaved: (value) { - leadBloc.currentEditLead['phone'] = value; - }, - ), - ), - ])), - ]))))), - ); - } - - Widget buildAddressBlock() { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 3; - }); - }, - onSwipeRight: (offset) { - setState(() { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _addressFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Address Line ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['address_line'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - leadBloc.currentEditLead['address_line'] = - value; - }, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - ), - ), - _errors['address_line'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['address_line'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Street ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: leadBloc.currentEditLead['street'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['street'] = value; - }, - ), - ), - _errors['street'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['street'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'City ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: leadBloc.currentEditLead['city'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['city'] = value; - }, - ), - ), - _errors['city'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['city'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'State ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: leadBloc.currentEditLead['state'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['state'] = value; - }, - ), - ), - _errors['state'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['state'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Pincode ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - leadBloc.currentEditLead['postcode'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - leadBloc.currentEditLead['postcode'] = value; - }, - ), - ), - _errors['postcode'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['postcode'][0], - style: TextStyle( - color: Colors.red[700], fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RichText( - text: TextSpan( - text: 'Country ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - height: screenHeight / 17, - child: Stack(children: [ - DropdownSearch( - items: (filter, infiniteScrollProps) => leadBloc.countries, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - leadBloc.currentEditLead['country'] = ""; - } else { - leadBloc.currentEditLead['country'] = - selection; - } - }, - selectedItem: - leadBloc.currentEditLead['country'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Country", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ])), - ])), - ])))), - ); - } - - Widget buildDescriptionBlock() { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: - Column( - children: [ - quill.QuillSimpleToolbar( - controller: _controller, - config: const quill.QuillSimpleToolbarConfig(), - ), - Expanded( - child: Container( - child: quill.QuillEditor.basic( - controller: _controller, - config: const quill.QuillEditorConfig()), - ), - ) - ], - ) - ), - ); - } - - @override - Widget build(BuildContext context) { - // Set readOnly property based on loading state - _controller.readOnly = _isLoading; - - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - leadBloc.cancelCurrentEditLead(); - leadBloc.currentEditLeadId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - leadBloc.currentEditLeadId == "" - ? 'Add Lead' - : "Edit Lead", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_leadFormKey.currentState != null) - _leadFormKey.currentState!.save(); - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - leadBloc.currentEditLead['description'] = - _controller.document.toPlainText(); - FocusScope.of(context).unfocus(); - if (!_isLoading) _submitForm(); // - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: !_isLoading - ? BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))) - : BoxDecoration(), - width: screenWidth * 0.15, - child: !_isLoading - ? Text( - 'Lead', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ) - : Container(), - ), - ), - GestureDetector( - onTap: () { - if (_leadFormKey.currentState != null) - _leadFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: !_isLoading - ? BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))) - : BoxDecoration(), - width: screenWidth * 0.15, - child: !_isLoading - ? Text( - 'Contact', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ) - : Container(), - ), - ), - GestureDetector( - onTap: () { - if (_leadFormKey.currentState != null) - _leadFormKey.currentState!.save(); - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: !_isLoading - ? BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 2 ? 3.0 : 0.0, - ))) - : BoxDecoration(), - width: screenWidth * 0.20, - child: !_isLoading - ? Text( - 'Address', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ) - : Container(), - ), - ), - GestureDetector( - onTap: () { - if (_leadFormKey.currentState != null) - _leadFormKey.currentState!.save(); - if (_contactFormKey.currentState != null) - _contactFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 3; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: !_isLoading - ? BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 3 ? 3.0 : 0.0, - ))) - : BoxDecoration(), - width: screenWidth * 0.25, - child: !_isLoading - ? Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 3 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ) - : Container(), - ), - ), - ], - ), - ), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_leadFormKey.currentState != null) { - if (!_leadFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _leadFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_contactFormKey.currentState != null) { - if (!_contactFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _contactFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 2; - }); - - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_addressFormKey.currentState != null) { - if (!_addressFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _addressFormKey.currentState!.save(); - - Map _result = {}; - if (leadBloc.currentEditLeadId != null && - leadBloc.currentEditLeadId != "") { - _result = await leadBloc.editLead(); - } else { - _result = await leadBloc.createLead(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - leadBloc.cancelCurrentEditLead(); - leadBloc.currentEditLeadId = ""; - showToaster(_result['message'], context); - leadBloc.openLeads.clear(); - leadBloc.offset = ""; - await leadBloc.fetchLeads(); - await FirebaseAnalytics.instance.logEvent(name: "Lead_Creatd"); - Navigator.pushReplacementNamed(context, '/leads_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _leadFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - for (var key in _contactFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 1; - }); - showToaster(_errors[key][0], context); - return; - } - } - for (var key in _addressFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 2; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/leads/lead_details.dart b/lib/ui/screens/leads/lead_details.dart deleted file mode 100644 index 774d3dc..0000000 --- a/lib/ui/screens/leads/lead_details.dart +++ /dev/null @@ -1,917 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/model/lead.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/flutter_svg.dart'; - -class LeadDetails extends StatefulWidget { - LeadDetails(); - @override - State createState() => _LeadDetailsState(); -} - -class _LeadDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Lead Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - leadBloc.currentEditLeadId = - leadBloc.currentLead!.id.toString(); - await leadBloc - .updateCurrentEditLead(leadBloc.currentLead!); - Navigator.pushNamed(context, '/leads_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - !_isLoading - ? Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Lead Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Attachment', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: - _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Notes', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ) - : Container(), - ], - ), - ), - Expanded( - child: !_isLoading - ? Container( - child: buildTopBar(), - color: Colors.white, - ) - : Container( - height: screenHeight, - width: screenWidth, - color: Colors.white)) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ])); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildLeadInfoBlock(); - } else if (_currentTabIndex == 1) { - return buildAttachmentBlock(); - } else if (_currentTabIndex == 2) { - return buildDescriptionBlock(); - } - } - - buildAttachmentBlock() { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - color: Colors.white, - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - child: Text("No Attachments Found."), - ), - ); - } - - buildDescriptionBlock() { - return SwipeDetector( - onSwipeRight: (offset) { - if (_currentTabIndex == 2) { - setState(() { - _currentTabIndex = 1; - }); - } - }, - child: Container( - height: screenHeight, - width: screenWidth, - color: Colors.white, - alignment: Alignment.center, - child: Text( - leadBloc.currentLead!.description != "" - ? leadBloc.currentLead!.description! - : "No Description Found", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22.0)), - ), - ); - } - - buildLeadInfoBlock() { - return SwipeDetector( - onSwipeLeft: (offset) { - if (_currentTabIndex == 0) { - setState(() { - _currentTabIndex = 1; - }); - } - }, - child: Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Text( - leadBloc.currentLead!.title!.allInCaps, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 10.0), - Row(children: [ - leadBloc.currentLead!.opportunityAmount != "" - ? Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: ColorBrightness.dark), - child: Text( - leadBloc.currentLead!.opportunityAmount!, - style: TextStyle( - color: Colors.white, fontSize: 15.0), - ), - ) - : Container(), - leadBloc.currentLead!.status != "" - ? Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: ColorBrightness.dark), - child: Text( - leadBloc.currentLead!.status!, - style: TextStyle( - color: Colors.white, fontSize: 15.0), - ), - ) - : Container(), - ]), - SizedBox(height: 10.0), - TagViewWidget(leadBloc.currentLead!.tags!), - SizedBox(height: 10.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: ProfilePicViewWidget(leadBloc - .currentLead!.assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser.firstName![0].inCaps - : assignedUser.profileUrl) - .toList())), - ], - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Container( - child: Text( - "Create Date", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Text( - leadBloc.currentLead!.createdOn!, - style: TextStyle( - color: Colors.grey, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - ], - ), - ), - Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - "Expected Close Date", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Text( - leadBloc.currentLead!.createdOn!, - style: TextStyle( - color: Colors.grey, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - ], - ), - ) - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Text( - "http://www.micropyramid.com", - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 30), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - leadBloc.currentLead!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${leadBloc.currentLead!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.email_outlined, - size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - leadBloc.currentLead!.email! == "" - ? "-----" - : leadBloc.currentLead!.email!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - leadBloc.currentLead!.phone! == "" - ? "------" - : leadBloc.currentLead!.phone!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Image.asset( - "assets/images/skype.png", - width: screenWidth / 22, - )), - Text( - leadBloc.currentLead!.skypeID == "" - ? " ---------" - : " " + leadBloc.currentLead!.skypeID!, - style: TextStyle( - color: leadBloc.currentLead!.skypeID != "" - ? Colors.blue - : Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Industry :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "product & services", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Pipeline :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "----------", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Probability :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "----------", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "First Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - leadBloc.currentLead!.firstName != "" - ? leadBloc.currentLead!.firstName! - : "-----", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Last Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - leadBloc.currentLead!.lastName! == "" - ? "-----" - : leadBloc.currentLead!.lastName!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Job Title :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - leadBloc.currentLead!.title! == "" - ? "-----" - : leadBloc.currentLead!.title!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - )), - SizedBox(height: 10), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column(children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Address :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "${leadBloc.currentLead!.addressLine}, ${leadBloc.currentLead!.street}, ${leadBloc.currentLead!.city}, ${leadBloc.currentLead!.state}, ${leadBloc.currentLead!.postcode}, ${leadBloc.currentLead!.country}.", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ])), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteLeadAlertDialog(context, leadBloc.currentLead!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))), - ); - } - - void showDeleteLeadAlertDialog(BuildContext context, Lead lead) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - lead.firstName != "" - ? lead.firstName!.capitalizeFirstofEach() - : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this lead?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteLead(lead); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteLead(Lead lead) async { - setState(() { - _isLoading = true; - }); - Map result = await leadBloc.deleteLead(lead); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - leadBloc.openLeads.clear(); - await leadBloc.fetchLeads(); - await FirebaseAnalytics.instance.logEvent(name: "Lead_Deleted"); - Navigator.pushReplacementNamed(context, '/leads_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, 'Something went wrong', lead); - } - } - - showErrorMessage(BuildContext context, msg, Lead lead) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteLead(lead); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/leads/leads_list.dart b/lib/ui/screens/leads/leads_list.dart deleted file mode 100644 index f157783..0000000 --- a/lib/ui/screens/leads/leads_list.dart +++ /dev/null @@ -1,868 +0,0 @@ -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -//import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:bottle_crm/model/lead.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; - -class LeadsList extends StatefulWidget { - LeadsList(); - @override - State createState() => _LeadsListState(); -} - -class _LeadsListState extends State { - var _currentTabIndex = 0; - final GlobalKey _filtersFormKey = GlobalKey(); - bool _isFilter = false; - List _openLeads = []; - List _closedLeads = []; - Map _filtersFormData = { - "title": "", - "source": null, - "assigned_to": [], - "status": null, - "tags": [] - }; - bool _isLoading = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - - @override - void initState() { - setState(() { - _openLeads = leadBloc.openLeads; - _closedLeads = leadBloc.closedLeads; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - leadBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await leadBloc.fetchLeads( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - leadBloc.offset = ""; - leadBloc.openLeads.clear(); - leadBloc.closedLeads.clear(); - await leadBloc.fetchLeads(filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['title'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter title", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['title'] = value; - }, - ), - ), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Status", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: leadBloc.status, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // leadBloc.currentEditLead["status"] = ""; - // } else { - // leadBloc.currentEditLead['status '] = - // selection; - // } - // }, - // selectedItem: - // leadBloc.currentEditLead['status '], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Status", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Source', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Source", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: leadBloc.source, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // leadBloc.currentEditLead["source"] = ""; - // } else { - // leadBloc.currentEditLead['source '] = - // selection; - // } - // }, - // selectedItem: - // leadBloc.currentEditLead['source '], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Source", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Source', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - SizedBox(height: 10.0), - Container( - padding: padding(), - child: Container( - width: screenWidth * 0.92, - child: Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Users", - ), - initialValue: _filtersFormData['assigned_to'], - onSaved: (value) { - if (value == null) return; - _filtersFormData['assigned_to'] = value; - }, - ), - ), - ), - ), - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - margin: EdgeInsets.only(bottom: 5.0), - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: leadBloc.filterTags, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text("Tags"), - initialValue: _filtersFormData['tags'], - onSaved: (value) { - if (value == null) return; - _filtersFormData['tags'] = value; - }, - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "title": "", - "source": null, - "assigned_to": [], - "status": null, - "tags": "" - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return _buildOpenLeadList(); - } else if (_currentTabIndex == 1) { - return _buildClosedLeadList(); - } - } - - Widget _buildOpenLeadList() { - return _openLeads.length != 0 - ? SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - _closedLeads = leadBloc.closedLeads; - }); - }, - child: Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _openLeads.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - leadBloc.currentLead = _openLeads[index]; - Navigator.pushNamed(context, '/lead_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: - BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - _openLeads[index].title!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - child: ProfilePicViewWidget( - _openLeads[index] - .assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser - .firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - Row( - children: [ - _openLeads[index].status != "" - ? Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, - vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: - ColorBrightness.light), - child: Text( - _openLeads[index].status == "" - ? "" - : _openLeads[index] - .status!, - style: TextStyle( - color: Colors.white, - fontSize: 15.0), - ), - ) - : Container(), - SizedBox(width: 10.0), - Container( - child: Text( - _openLeads[index] - .opportunityAmount == - "" - ? "₹0" - : "₹" + - _openLeads[index] - .opportunityAmount!, - style: TextStyle( - color: Theme.of(context) - .primaryColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w600)), - ) - ], - ), - ], - ), - ) - ], - ), - )); - }), - ), - ) - : SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - color: Colors.white, - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Open Leas Found.'), - ), - ); - } - - Widget _buildClosedLeadList() { - return _closedLeads.length != 0 - ? SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _closedLeads.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - leadBloc.currentLead = _closedLeads[index]; - Navigator.pushNamed(context, '/lead_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: - BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - _closedLeads[index].title!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - child: ProfilePicViewWidget( - _closedLeads[index] - .assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser - .firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - Row( - children: [ - _closedLeads[index].status != "" - ? Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, - vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: - ColorBrightness.light), - child: Text( - _closedLeads[index].status == - "" - ? "" - : _closedLeads[index] - .status!, - style: TextStyle( - color: Colors.white, - fontSize: 15.0), - ), - ) - : Container(), - SizedBox(width: 10.0), - Container( - child: Text( - _closedLeads[index] - .opportunityAmount == - "" - ? "₹0" - : "₹" + - _closedLeads[index] - .opportunityAmount!, - style: TextStyle( - color: Theme.of(context) - .primaryColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w600)), - ) - ], - ), - ], - ), - ) - ], - ), - )); - }), - ), - ) - : SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - color: Colors.white, - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Closed Leads Found.'), - ), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - currentBottomNavigationIndex == "4" - ? Navigator.pushReplacementNamed( - context, "/dashboard") - : Navigator.pushReplacementNamed( - context, "/more_options"); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Leads', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - if (_currentTabIndex != 0) { - setState(() { - _currentTabIndex = 0; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Open', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_currentTabIndex != 1) { - setState(() { - _currentTabIndex = 1; - _closedLeads = leadBloc.closedLeads; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Closed', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ) - ], - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, - child: GestureDetector(child: buildTopBar()), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - leadBloc.currentEditLeadId = ""; - if (leadBloc.openLeads.length == 0 && - leadBloc.closedLeads.length == 0) { - showAlertDialog(context); - } else { - Navigator.pushNamed(context, '/leads_create'); - } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any leads, Please create lead first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/leads_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/modern/authentication/login_screen.dart b/lib/ui/screens/modern/authentication/login_screen.dart deleted file mode 100644 index ff1bfd7..0000000 --- a/lib/ui/screens/modern/authentication/login_screen.dart +++ /dev/null @@ -1,490 +0,0 @@ -import 'package:bottle_crm/responsive.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:flutter_svg/svg.dart'; - -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class LoginScreen extends StatefulWidget { - const LoginScreen({Key? key}) : super(key: key); - - @override - State createState() => _LoginScreenState(); -} - -class _LoginScreenState extends State { - bool _isLoading = false; - String _errorMessage = ''; - - @override - void initState() { - super.initState(); - // Clear all stored data when login page opens - authBloc.clearAllStoredData(); - } - - - _googleLogin() async { - setState(() { - _isLoading = true; - }); - - try { - Map result = await authBloc.googleLogin(); - if (result['error'] == false) { - setState(() { - _errorMessage = ''; - }); - await FirebaseAnalytics.instance.logEvent(name: "google_login"); - Navigator.pushNamedAndRemoveUntil( - context, '/organization_selection', (route) => false); - } else { - setState(() { - _errorMessage = result['message'] ?? 'Google login failed'; - }); - } - } catch (e) { - setState(() { - _errorMessage = 'Google login failed. Please try again.'; - }); - } - - setState(() { - _isLoading = false; - }); - } - - - Widget loginWidget() { - return Responsive( - mobile: buildMobileScreen(), - tablet: buildTabletScreen(), - desktop: Container()); - } - - buildMobileScreen() { - return SingleChildScrollView( - child: Container( - height: screenHeight, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Theme.of(context).primaryColor, - Theme.of(context).primaryColor.withOpacity(0.8), - ], - ), - ), - child: Column( - children: [ - SizedBox(height: screenHeight * 0.08), - // Logo and Branding Section - Container( - padding: EdgeInsets.symmetric(horizontal: 30.0), - child: Column( - children: [ - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.4, - color: Colors.white, - ), - SizedBox(height: 20), - Text( - 'BottleCRM', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 10, - fontWeight: FontWeight.bold, - letterSpacing: 1.2, - ), - ), - SizedBox(height: 10), - Text( - 'Free CRM for startups and enterprises', - style: TextStyle( - color: Colors.white.withOpacity(0.9), - fontSize: screenWidth / 25, - fontWeight: FontWeight.w400, - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - SizedBox(height: screenHeight * 0.08), - // Login Card - Expanded( - child: Container( - width: screenWidth, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(30), - topRight: Radius.circular(30), - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 20, - offset: Offset(0, -5), - ), - ], - ), - child: Container( - padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 40.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Welcome Back!', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 12, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 10), - Text( - 'Sign in to continue managing your business', - style: TextStyle( - color: Colors.grey[600], - fontSize: screenWidth / 26, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: screenHeight * 0.05), - _errorMessage != '' - ? Container( - margin: EdgeInsets.only(bottom: 20.0), - padding: EdgeInsets.all(12.0), - decoration: BoxDecoration( - color: Colors.red.withOpacity(0.1), - borderRadius: BorderRadius.circular(8.0), - border: Border.all(color: Colors.red.withOpacity(0.3)), - ), - child: Row( - children: [ - Icon(Icons.error_outline, color: Colors.red, size: 20), - SizedBox(width: 8), - Expanded( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red[700], - fontSize: screenWidth / 30, - ), - ), - ), - ], - ), - ) - : SizedBox(), - !_isLoading - ? Container( - width: screenWidth, - height: 56, - child: ElevatedButton( - onPressed: _googleLogin, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black87, - elevation: 2, - shadowColor: Colors.black26, - side: BorderSide(color: Colors.grey[300]!, width: 1), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/google-icon.png', - width: 24, - height: 24, - ), - SizedBox(width: 16), - Text( - 'Continue with Google', - style: TextStyle( - fontSize: screenWidth / 22, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ) - : Container( - height: 56, - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Theme.of(context).primaryColor), - ), - ), - ), - SizedBox(height: screenHeight * 0.04), - Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.withOpacity(0.05), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.blue.withOpacity(0.2)), - ), - child: Row( - children: [ - Icon(Icons.info_outline, color: Colors.blue, size: 20), - SizedBox(width: 8), - Expanded( - child: Text( - 'Secure sign-in powered by Google OAuth 2.0', - style: TextStyle( - color: Colors.blue[700], - fontSize: screenWidth / 32, - ), - ), - ), - ], - ), - ), - SizedBox( - height: screenHeight * 0.05, - ), - ], - ), - ), - ), - ), - ], - ), - ), - ); - } - - buildTabletScreen() { - return Container( - height: screenHeight, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Theme.of(context).primaryColor, - Theme.of(context).primaryColor, - ], - ), - ), - child: Row( - children: [ - // Left side - Branding - Expanded( - flex: 1, - child: Container( - padding: EdgeInsets.all(40), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SvgPicture.asset( - 'assets/images/logo.svg', - width: screenWidth * 0.15, - colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), - ), - SizedBox(height: 30), - Text( - 'BottleCRM', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold, - letterSpacing: 1.2, - ), - ), - SizedBox(height: 15), - Text( - 'Free CRM for startups and enterprises', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 50, - fontWeight: FontWeight.w400, - height: 1.5, - ), - ), - SizedBox(height: 30), - Text( - 'Manage your customers, leads, and opportunities all in one place.', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 60, - height: 1.6, - ), - ), - ], - ), - ), - ), - // Right side - Login Form - Expanded( - flex: 1, - child: Container( - margin: EdgeInsets.all(40), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.black12, - blurRadius: 20, - offset: Offset(0, 10), - ), - ], - ), - child: Container( - padding: EdgeInsets.all(40), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Welcome Back!', - style: TextStyle( - color: Colors.black87, - fontSize: screenWidth / 25, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 10), - Text( - 'Sign in to continue managing your business', - style: TextStyle( - color: Colors.grey[600], - fontSize: screenWidth / 55, - ), - textAlign: TextAlign.center, - ), - SizedBox(height: 40), - _errorMessage != '' - ? Container( - margin: EdgeInsets.only(bottom: 20.0), - padding: EdgeInsets.all(12.0), - decoration: BoxDecoration( - color: Colors.red.shade50, - borderRadius: BorderRadius.circular(8.0), - border: Border.all(color: Colors.red.shade200), - ), - child: Row( - children: [ - Icon(Icons.error_outline, color: Colors.red, size: 18), - SizedBox(width: 8), - Expanded( - child: Text( - _errorMessage, - style: TextStyle( - color: Colors.red[700], - fontSize: screenWidth / 60, - ), - ), - ), - ], - ), - ) - : SizedBox(), - !_isLoading - ? Container( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: _googleLogin, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black87, - elevation: 2, - shadowColor: Colors.black26, - side: BorderSide(color: Colors.grey[300]!, width: 1), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/google-icon.png', - width: 24, - height: 24, - ), - SizedBox(width: 16), - Text( - 'Continue with Google', - style: TextStyle( - fontSize: screenWidth / 45, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ) - : Container( - height: 56, - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Theme.of(context).primaryColor), - ), - ), - ), - SizedBox(height: 30), - Container( - padding: EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue.shade50, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.blue.shade200), - ), - child: Row( - children: [ - Icon(Icons.info_outline, color: Colors.blue, size: 18), - SizedBox(width: 8), - Expanded( - child: Text( - 'Secure sign-in powered by Google OAuth 2.0', - style: TextStyle( - color: Colors.blue[700], - fontSize: screenWidth / 65, - ), - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - screenWidth = MediaQuery.of(context).size.width; - screenHeight = MediaQuery.of(context).size.height; - return Scaffold( - body: loginWidget(), - ); - } -} diff --git a/lib/ui/screens/modern/authentication/organization_selection_screen.dart b/lib/ui/screens/modern/authentication/organization_selection_screen.dart deleted file mode 100644 index ae2aeb0..0000000 --- a/lib/ui/screens/modern/authentication/organization_selection_screen.dart +++ /dev/null @@ -1,716 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/model/organization.dart'; -import 'package:bottle_crm/responsive.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class OrganizationSelectionScreen extends StatefulWidget { - const OrganizationSelectionScreen({Key? key}) : super(key: key); - - @override - State createState() => _OrganizationSelectionScreenState(); -} - -class _OrganizationSelectionScreenState extends State - with TickerProviderStateMixin { - List organizations = []; - bool isLoading = false; - int? selectedIndex; - String searchQuery = ''; - late AnimationController _fadeController; - late AnimationController _slideController; - late AnimationController _searchController; - late Animation _fadeAnimation; - late Animation _slideAnimation; - late Animation _searchAnimation; - final TextEditingController _searchTextController = TextEditingController(); - final FocusNode _searchFocusNode = FocusNode(); - - List get filteredOrganizations { - if (searchQuery.isEmpty) return organizations; - return organizations.where((org) => - org.name?.toLowerCase().contains(searchQuery.toLowerCase()) ?? false - ).toList(); - } - - @override - void initState() { - super.initState(); - _setupAnimations(); - _loadOrganizations(); - } - - void _setupAnimations() { - _fadeController = AnimationController( - duration: const Duration(milliseconds: 800), - vsync: this, - ); - _slideController = AnimationController( - duration: const Duration(milliseconds: 600), - vsync: this, - ); - _searchController = AnimationController( - duration: const Duration(milliseconds: 400), - vsync: this, - ); - - _fadeAnimation = Tween( - begin: 0.0, - end: 1.0, - ).animate(CurvedAnimation( - parent: _fadeController, - curve: Curves.easeInOut, - )); - - _slideAnimation = Tween( - begin: const Offset(0, 0.3), - end: Offset.zero, - ).animate(CurvedAnimation( - parent: _slideController, - curve: Curves.easeOutCubic, - )); - - _searchAnimation = Tween( - begin: 0.0, - end: 1.0, - ).animate(CurvedAnimation( - parent: _searchController, - curve: Curves.easeInOut, - )); - } - - void _loadOrganizations() { - setState(() { - organizations = authBloc.companies; - }); - - // Start animations - _fadeController.forward(); - Future.delayed(const Duration(milliseconds: 200), () { - _slideController.forward(); - }); - Future.delayed(const Duration(milliseconds: 600), () { - _searchController.forward(); - }); - } - - @override - void dispose() { - _fadeController.dispose(); - _slideController.dispose(); - _searchController.dispose(); - _searchTextController.dispose(); - _searchFocusNode.dispose(); - super.dispose(); - } - - Future _selectOrganization(int index) async { - if (isLoading) return; - - // Haptic feedback - HapticFeedback.lightImpact(); - - setState(() { - selectedIndex = index; - isLoading = true; - }); - - try { - final SharedPreferences prefs = await SharedPreferences.getInstance(); - await prefs.setString('org', organizations[index].id!); - authBloc.selectedOrganization = organizations[index]; - - // Fetch required data - await fetchRequiredData(); - - // Analytics - await FirebaseAnalytics.instance.logEvent( - name: "${organizations[index].name!}_Selected" - ); - - // Navigate with a slight delay for visual feedback - await Future.delayed(const Duration(milliseconds: 300)); - - if (mounted) { - Navigator.pushNamedAndRemoveUntil( - context, - '/dashboard', - (route) => false - ); - } - } catch (e) { - if (mounted) { - setState(() { - selectedIndex = null; - isLoading = false; - }); - - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Failed to select organization. Please try again.'), - backgroundColor: Colors.red[600], - behavior: SnackBarBehavior.floating, - ), - ); - } - } - } - - @override - Widget build(BuildContext context) { - return PopScope( - canPop: false, - onPopInvokedWithResult: (didPop, result) async { - if (!didPop) { - bool shouldPop = await onWillPop(); - if (shouldPop) Navigator.of(context).pop(); - } - }, - child: Scaffold( - backgroundColor: const Color(0xFF4980FF), - body: SafeArea( - child: Column( - children: [ - _buildHeader(), - Expanded( - child: _buildOrganizationsList(), - ), - ], - ), - ), - ), - ); - } - - Widget _buildHeader() { - return FadeTransition( - opacity: _fadeAnimation, - child: Container( - padding: const EdgeInsets.all(24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 20), - Text( - 'Welcome back!', - style: TextStyle( - color: Colors.white.withOpacity(0.9), - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 8), - Row( - children: [ - const Expanded( - child: Text( - 'Select your organization', - style: TextStyle( - color: Colors.white, - fontSize: 28, - fontWeight: FontWeight.bold, - height: 1.2, - ), - ), - ), - if (organizations.length > 1) - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: Colors.white.withOpacity(0.3), - ), - ), - child: Text( - '${organizations.length} available', - style: TextStyle( - color: Colors.white.withOpacity(0.9), - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - 'Choose the organization you want to access', - style: TextStyle( - color: Colors.white.withOpacity(0.8), - fontSize: 16, - height: 1.4, - ), - ), - ], - ), - ), - ); - } - - Widget _buildOrganizationsList() { - return SlideTransition( - position: _slideAnimation, - child: FadeTransition( - opacity: _fadeAnimation, - child: Container( - decoration: const BoxDecoration( - color: Color(0xFFF8F9FA), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - ), - child: Column( - children: [ - const SizedBox(height: 8), - // Drag indicator - Container( - width: 40, - height: 4, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(2), - ), - ), - const SizedBox(height: 16), - // Search bar (if organizations > 3) - if (organizations.length > 3) _buildSearchBar(), - const SizedBox(height: 8), - Expanded( - child: organizations.isNotEmpty - ? _buildOrganizationsGrid() - : _buildEmptyState(), - ), - ], - ), - ), - ), - ); - } - - Widget _buildSearchBar() { - return SlideTransition( - position: Tween( - begin: const Offset(0, -0.5), - end: Offset.zero, - ).animate(_searchAnimation), - child: FadeTransition( - opacity: _searchAnimation, - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 24), - padding: const EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: _searchFocusNode.hasFocus - ? const Color(0xFF4980FF).withOpacity(0.3) - : Colors.transparent, - ), - ), - child: Row( - children: [ - Icon( - Icons.search, - color: Colors.grey[600], - size: 20, - ), - const SizedBox(width: 12), - Expanded( - child: TextField( - controller: _searchTextController, - focusNode: _searchFocusNode, - onChanged: (value) { - setState(() { - searchQuery = value; - }); - }, - decoration: const InputDecoration( - hintText: 'Search organizations...', - border: InputBorder.none, - hintStyle: TextStyle( - fontSize: 16, - color: Colors.grey, - ), - ), - style: const TextStyle( - fontSize: 16, - color: Colors.black87, - ), - ), - ), - if (searchQuery.isNotEmpty) - GestureDetector( - onTap: () { - _searchTextController.clear(); - setState(() { - searchQuery = ''; - }); - }, - child: Icon( - Icons.clear, - color: Colors.grey[600], - size: 20, - ), - ), - ], - ), - ), - ), - ); - } - - Widget _buildOrganizationsGrid() { - final orgsToShow = filteredOrganizations; - - if (orgsToShow.isEmpty && searchQuery.isNotEmpty) { - return _buildNoSearchResults(); - } - - return Responsive( - mobile: _buildMobileList(orgsToShow), - tablet: _buildTabletGrid(orgsToShow), - desktop: _buildDesktopGrid(orgsToShow), - ); - } - - Widget _buildMobileList(List orgs) { - return ListView.builder( - padding: const EdgeInsets.symmetric(horizontal: 24), - itemCount: orgs.length, - itemBuilder: (context, index) { - final orgIndex = organizations.indexOf(orgs[index]); - return AnimatedContainer( - duration: Duration(milliseconds: 100 + (index * 50)), - curve: Curves.easeOutBack, - child: _buildOrganizationCard(orgIndex, true, orgs[index]), - ); - }, - ); - } - - Widget _buildTabletGrid(List orgs) { - return GridView.builder( - padding: const EdgeInsets.symmetric(horizontal: 24), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 16, - mainAxisSpacing: 16, - childAspectRatio: 2.5, - ), - itemCount: orgs.length, - itemBuilder: (context, index) { - final orgIndex = organizations.indexOf(orgs[index]); - return AnimatedContainer( - duration: Duration(milliseconds: 100 + (index * 50)), - curve: Curves.easeOutBack, - child: _buildOrganizationCard(orgIndex, false, orgs[index]), - ); - }, - ); - } - - Widget _buildDesktopGrid(List orgs) { - return GridView.builder( - padding: const EdgeInsets.symmetric(horizontal: 32), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - crossAxisSpacing: 20, - mainAxisSpacing: 20, - childAspectRatio: 2.2, - ), - itemCount: orgs.length, - itemBuilder: (context, index) { - final orgIndex = organizations.indexOf(orgs[index]); - return AnimatedContainer( - duration: Duration(milliseconds: 100 + (index * 50)), - curve: Curves.easeOutBack, - child: _buildOrganizationCard(orgIndex, false, orgs[index]), - ); - }, - ); - } - - Widget _buildOrganizationCard(int index, bool isList, Organization organization) { - final isSelected = selectedIndex == index; - final isAdmin = organization.role == 'ADMIN'; - - return AnimatedContainer( - duration: const Duration(milliseconds: 200), - margin: EdgeInsets.only(bottom: isList ? 16 : 0), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => _selectOrganization(index), - borderRadius: BorderRadius.circular(20), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: isSelected ? const Color(0xFF4980FF) : Colors.white, - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: isSelected - ? const Color(0xFF4980FF) - : Colors.grey.withOpacity(0.1), - width: isSelected ? 2 : 1, - ), - boxShadow: [ - BoxShadow( - color: isSelected - ? const Color(0xFF4980FF).withOpacity(0.3) - : Colors.black.withOpacity(0.04), - blurRadius: isSelected ? 20 : 8, - offset: Offset(0, isSelected ? 8 : 2), - ), - ], - ), - child: Row( - children: [ - // Organization Avatar - Container( - width: 56, - height: 56, - decoration: BoxDecoration( - color: isSelected - ? Colors.white.withOpacity(0.2) - : const Color(0xFF4980FF).withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - ), - child: Center( - child: Text( - organization.name?.isNotEmpty == true - ? organization.name![0].toUpperCase() - : '?', - style: TextStyle( - color: isSelected - ? Colors.white - : const Color(0xFF4980FF), - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 16), - // Organization Info - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - organization.name ?? 'Unknown Organization', - style: TextStyle( - color: isSelected ? Colors.white : Colors.grey[800], - fontSize: 18, - fontWeight: FontWeight.bold, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), - decoration: BoxDecoration( - color: isSelected - ? Colors.white.withOpacity(0.2) - : isAdmin - ? const Color(0xFF10B981).withOpacity(0.1) - : Colors.grey.withOpacity(0.1), - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: isSelected - ? Colors.white.withOpacity(0.3) - : isAdmin - ? const Color(0xFF10B981).withOpacity(0.3) - : Colors.grey.withOpacity(0.3), - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - isAdmin ? Icons.admin_panel_settings : Icons.person, - size: 14, - color: isSelected - ? Colors.white - : isAdmin - ? const Color(0xFF10B981) - : Colors.grey[600], - ), - const SizedBox(width: 4), - Text( - organization.role ?? 'USER', - style: TextStyle( - color: isSelected - ? Colors.white - : isAdmin - ? const Color(0xFF10B981) - : Colors.grey[600], - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ], - ), - ), - // Loading indicator or arrow - if (isLoading && isSelected) - const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation(Colors.white), - ), - ) - else - Icon( - Icons.arrow_forward_ios, - color: isSelected - ? Colors.white.withOpacity(0.8) - : Colors.grey[400], - size: 16, - ), - ], - ), - ), - ), - ), - ); - } - - Widget _buildNoSearchResults() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 120, - height: 120, - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(60), - ), - child: Icon( - Icons.search_off_outlined, - size: 60, - color: Colors.grey[400], - ), - ), - const SizedBox(height: 24), - Text( - 'No Results Found', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.grey[800], - ), - ), - const SizedBox(height: 8), - Text( - 'Try adjusting your search terms\nor check the spelling.', - style: TextStyle( - fontSize: 16, - color: Colors.grey[600], - height: 1.5, - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 32), - OutlinedButton.icon( - onPressed: () { - _searchTextController.clear(); - setState(() { - searchQuery = ''; - }); - }, - icon: const Icon(Icons.clear_all), - label: const Text('Clear Search'), - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF4980FF), - side: const BorderSide(color: Color(0xFF4980FF)), - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ], - ), - ); - } - - Widget _buildEmptyState() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 120, - height: 120, - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(60), - ), - child: Icon( - Icons.business_outlined, - size: 60, - color: Colors.grey[400], - ), - ), - const SizedBox(height: 24), - Text( - 'No Organizations Found', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.grey[800], - ), - ), - const SizedBox(height: 8), - Text( - 'Please contact your administrator to get access\nto an organization.', - style: TextStyle( - fontSize: 16, - color: Colors.grey[600], - height: 1.5, - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 32), - OutlinedButton.icon( - onPressed: () { - Navigator.pushNamedAndRemoveUntil( - context, - '/login', - (route) => false, - ); - }, - icon: const Icon(Icons.refresh), - label: const Text('Try Again'), - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF4980FF), - side: const BorderSide(color: Color(0xFF4980FF)), - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ], - ), - ); - } -} \ No newline at end of file diff --git a/lib/ui/screens/modern/dashboard_controller.dart b/lib/ui/screens/modern/dashboard_controller.dart deleted file mode 100644 index b27b598..0000000 --- a/lib/ui/screens/modern/dashboard_controller.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/foundation.dart'; -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/opportunities.dart'; -import 'package:bottle_crm/services/crm_services.dart'; -import 'dashboard_state.dart'; - -class DashboardController extends ChangeNotifier { - DashboardState _state = DashboardInitial(); - - DashboardState get state => _state; - - bool get isLoading => _state is DashboardLoading; - bool get hasError => _state is DashboardError; - bool get hasData => _state is DashboardLoaded; - bool get isEmpty => _state is DashboardEmpty; - - DashboardLoaded? get data => _state is DashboardLoaded ? _state as DashboardLoaded : null; - String get errorMessage => _state is DashboardError ? (_state as DashboardError).message : ''; - - void _setState(DashboardState newState) { - _state = newState; - notifyListeners(); - } - - Future loadDashboard() async { - if (_state is DashboardLoading) return; // Prevent multiple loading calls - - _setState(DashboardLoading()); - - try { - final response = await CrmService().getDashboardDetails(); - final res = json.decode(response.body); - - if (response.statusCode != 200) { - throw Exception('Failed to load dashboard: ${response.statusCode}'); - } - - // Parse accounts - final List accounts = []; - if (res['accounts'] != null) { - for (var accountData in res['accounts']) { - try { - accounts.add(Account.fromJson(accountData)); - } catch (e) { - debugPrint('Error parsing account: $e'); - } - } - } - - // Parse contacts - final List contacts = []; - if (res['contacts'] != null) { - for (var contactData in res['contacts']) { - try { - contacts.add(Contact.fromJson(contactData)); - } catch (e) { - debugPrint('Error parsing contact: $e'); - } - } - } - - // Parse opportunities - final List opportunities = []; - if (res['opportunities'] != null) { - for (var opportunityData in res['opportunities']) { - try { - opportunities.add(Opportunity.fromJson(opportunityData)); - } catch (e) { - debugPrint('Error parsing opportunity: $e'); - } - } - } - - // Check if all data is empty - final accountsCount = res['accounts_count'] ?? 0; - final contactsCount = res['contacts_count'] ?? 0; - final leadsCount = res['leads_count'] ?? 0; - final opportunitiesCount = res['opportunities_count'] ?? 0; - - final totalCount = accountsCount + contactsCount + leadsCount + opportunitiesCount; - - if (totalCount == 0 && accounts.isEmpty && contacts.isEmpty && opportunities.isEmpty) { - _setState(DashboardEmpty()); - return; - } - - _setState(DashboardLoaded( - accounts: accounts, - contacts: contacts, - opportunities: opportunities, - accountsCount: accountsCount, - contactsCount: contactsCount, - leadsCount: leadsCount, - opportunitiesCount: opportunitiesCount, - )); - - } catch (e) { - debugPrint('Dashboard loading error: $e'); - String errorMessage = 'Failed to load dashboard data'; - - if (e.toString().contains('Network')) { - errorMessage = 'Network error. Please check your connection.'; - } else if (e.toString().contains('401')) { - errorMessage = 'Authentication error. Please log in again.'; - } else if (e.toString().contains('403')) { - errorMessage = 'Access denied. Please check your permissions.'; - } else if (e.toString().contains('500')) { - errorMessage = 'Server error. Please try again later.'; - } - - _setState(DashboardError(errorMessage, e is Exception ? e : Exception(e.toString()))); - } - } - - Future refresh() async { - await loadDashboard(); - } - - void clearError() { - if (_state is DashboardError) { - _setState(DashboardInitial()); - } - } - - // Helper methods for backward compatibility with existing dashboard bloc - Map get dashboardData { - if (_state is DashboardLoaded) { - return (_state as DashboardLoaded).toMap(); - } - return {}; - } -} \ No newline at end of file diff --git a/lib/ui/screens/modern/dashboard_screen.dart b/lib/ui/screens/modern/dashboard_screen.dart deleted file mode 100644 index 4f7769c..0000000 --- a/lib/ui/screens/modern/dashboard_screen.dart +++ /dev/null @@ -1,547 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:bottle_crm/responsive.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'dashboard_controller.dart'; - -class ModernDashboardScreen extends StatefulWidget { - const ModernDashboardScreen({Key? key}) : super(key: key); - - @override - State createState() => _ModernDashboardScreenState(); -} - -class _ModernDashboardScreenState extends State - with TickerProviderStateMixin { - late TabController _tabController; - late DashboardController _dashboardController; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 3, vsync: this); - _dashboardController = DashboardController(); - _dashboardController.addListener(_onDashboardStateChanged); - _loadDashboardData(); - } - - @override - void dispose() { - _tabController.dispose(); - _dashboardController.removeListener(_onDashboardStateChanged); - _dashboardController.dispose(); - super.dispose(); - } - - void _onDashboardStateChanged() { - if (mounted) { - setState(() {}); - } - } - - Future _loadDashboardData() async { - await _dashboardController.loadDashboard(); - } - - @override - Widget build(BuildContext context) { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.portraitUp, - DeviceOrientation.portraitDown - ]); - - return PopScope( - canPop: false, - onPopInvokedWithResult: (didPop, result) { - if (!didPop) { - Navigator.pushNamedAndRemoveUntil( - context, '/organization_selection', (route) => false); - } - }, - child: Scaffold( - backgroundColor: const Color(0xFFF8F9FA), - appBar: _buildAppBar(), - body: RefreshIndicator( - onRefresh: _loadDashboardData, - child: _dashboardController.isLoading - ? const Center(child: CircularProgressIndicator()) - : _dashboardController.hasError - ? _buildErrorState() - : _dashboardController.isEmpty - ? _buildEmptyDashboard() - : _buildDashboardContent(), - ), - bottomNavigationBar: BottomNavigationBarWidget(), - ), - ); - } - - PreferredSizeWidget _buildAppBar() { - return AppBar( - elevation: 0, - backgroundColor: const Color(0xFF4980FF), - systemOverlayStyle: SystemUiOverlayStyle.light, - title: const Text( - 'Dashboard', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.w600, - ), - ), - automaticallyImplyLeading: false, - actions: [ - IconButton( - icon: const Icon(Icons.refresh, color: Colors.white), - onPressed: _loadDashboardData, - ), - ], - ); - } - - Widget _buildErrorState() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.error_outline, - size: 64, - color: Colors.grey[400], - ), - const SizedBox(height: 16), - Text( - _dashboardController.errorMessage, - style: TextStyle( - fontSize: 16, - color: Colors.grey[600], - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 24), - ElevatedButton( - onPressed: _loadDashboardData, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF4980FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: const Text('Retry'), - ), - ], - ), - ); - } - - Widget _buildEmptyDashboard() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.dashboard_outlined, - size: 64, - color: Colors.grey[400], - ), - const SizedBox(height: 16), - Text( - 'Welcome to BottleCRM!', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.grey[700], - ), - ), - const SizedBox(height: 8), - Text( - 'Start by adding your first account, contact, or lead', - style: TextStyle( - fontSize: 16, - color: Colors.grey[600], - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 24), - ElevatedButton( - onPressed: () => Navigator.pushNamed(context, '/accounts_list'), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF4980FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: const Text('Get Started'), - ), - ], - ), - ); - } - - Widget _buildDashboardContent() { - return Responsive( - mobile: _buildMobileLayout(), - tablet: _buildTabletLayout(), - desktop: _buildDesktopLayout(), - ); - } - - Widget _buildMobileLayout() { - return SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildStatsGrid(), - const SizedBox(height: 24), - _buildRecentSection(), - ], - ), - ); - } - - Widget _buildTabletLayout() { - return SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - padding: const EdgeInsets.all(24), - child: Column( - children: [ - _buildStatsGrid(), - const SizedBox(height: 32), - _buildRecentSection(), - ], - ), - ); - } - - Widget _buildDesktopLayout() { - return SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - padding: const EdgeInsets.all(32), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: 2, - child: Column( - children: [ - _buildStatsGrid(), - const SizedBox(height: 32), - ], - ), - ), - const SizedBox(width: 32), - Expanded( - flex: 3, - child: _buildRecentSection(), - ), - ], - ), - ); - } - - Widget _buildStatsGrid() { - final isMobile = Responsive.isMobile(context); - - return GridView.count( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - crossAxisCount: isMobile ? 2 : 4, - crossAxisSpacing: 16, - mainAxisSpacing: 16, - childAspectRatio: isMobile ? 1.2 : 1.1, - children: [ - _buildModernStatCard( - label: 'Accounts', - count: _dashboardController.data?.accountsCount ?? 0, - icon: 'assets/images/accounts_color.svg', - color: const Color(0xFF4CAF50), - onTap: () => Navigator.pushNamed(context, '/accounts_list'), - ), - _buildModernStatCard( - label: 'Contacts', - count: _dashboardController.data?.contactsCount ?? 0, - icon: 'assets/images/identification.svg', - color: const Color(0xFF2196F3), - onTap: () => Navigator.pushNamed(context, '/contacts_list'), - ), - _buildModernStatCard( - label: 'Leads', - count: _dashboardController.data?.leadsCount ?? 0, - icon: 'assets/images/flag.svg', - color: const Color(0xFFFF9800), - onTap: () => Navigator.pushNamed(context, '/leads_list'), - ), - _buildModernStatCard( - label: 'Opportunities', - count: _dashboardController.data?.opportunitiesCount ?? 0, - icon: 'assets/images/opportunities_color.svg', - color: const Color(0xFF9C27B0), - onTap: () => Navigator.pushNamed(context, '/opportunities_list'), - ), - ], - ); - } - - Widget _buildModernStatCard({ - required String label, - required int count, - required String icon, - required Color color, - required VoidCallback onTap, - }) { - return Material( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - elevation: 2, - shadowColor: Colors.black.withOpacity(0.05), - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(16), - child: Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - border: Border.all(color: color.withOpacity(0.1)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: color.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: SvgPicture.asset( - icon, - width: 24, - height: 24, - colorFilter: ColorFilter.mode(color, BlendMode.srcIn), - ), - ), - ), - const SizedBox(height: 12), - Text( - count.toString(), - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.grey[800], - ), - ), - const SizedBox(height: 4), - Text( - label, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Colors.grey[600], - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - ), - ); - } - - Widget _buildRecentSection() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Recent Activity', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.grey[800], - ), - ), - const SizedBox(height: 16), - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - TabBar( - controller: _tabController, - indicator: UnderlineTabIndicator( - borderSide: const BorderSide( - width: 3, - color: Color(0xFF4980FF), - ), - insets: const EdgeInsets.symmetric(horizontal: 16), - ), - labelColor: const Color(0xFF4980FF), - unselectedLabelColor: Colors.grey[600], - labelStyle: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - ), - unselectedLabelStyle: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - ), - tabs: const [ - Tab(text: 'Accounts'), - Tab(text: 'Contacts'), - Tab(text: 'Opportunities'), - ], - ), - SizedBox( - height: 400, - child: TabBarView( - controller: _tabController, - children: [ - _buildRecentList('accounts'), - _buildRecentList('contacts'), - _buildRecentList('opportunities'), - ], - ), - ), - ], - ), - ), - ], - ); - } - - Widget _buildRecentList(String type) { - List? data; - - switch (type) { - case 'accounts': - data = _dashboardController.data?.accounts; - break; - case 'contacts': - data = _dashboardController.data?.contacts; - break; - case 'opportunities': - data = _dashboardController.data?.opportunities; - break; - } - - if (data == null || data.isEmpty) { - return _buildEmptyState(type); - } - - return ListView.separated( - padding: const EdgeInsets.all(16), - itemCount: data.length, - separatorBuilder: (context, index) => const Divider(height: 1), - itemBuilder: (context, index) { - return _buildRecentListItem(data![index], type); - }, - ); - } - - Widget _buildEmptyState(String type) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.inbox_outlined, - size: 48, - color: Colors.grey[400], - ), - const SizedBox(height: 16), - Text( - 'No recent $type', - style: TextStyle( - fontSize: 16, - color: Colors.grey[600], - ), - ), - ], - ), - ); - } - - Widget _buildRecentListItem(dynamic item, String type) { - String name = ''; - String subtitle = ''; - String? imageUrl; - - switch (type) { - case 'accounts': - name = item.name ?? ''; - subtitle = item.email ?? ''; - imageUrl = item.createdBy?.profileUrl; - break; - case 'contacts': - name = '${item.firstName ?? ''} ${item.lastName ?? ''}'.trim(); - subtitle = item.primaryEmail ?? ''; - imageUrl = item.createdBy?.profileUrl; - break; - case 'opportunities': - name = item.name ?? ''; - subtitle = item.amount?.toString() ?? ''; - imageUrl = item.createdBy?.profileUrl; - break; - } - - return ListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - leading: CircleAvatar( - radius: 20, - backgroundColor: const Color(0xFF4980FF).withOpacity(0.1), - backgroundImage: imageUrl != null ? NetworkImage(imageUrl) : null, - child: imageUrl == null - ? Text( - name.isNotEmpty ? name[0].toUpperCase() : '?', - style: const TextStyle( - color: Color(0xFF4980FF), - fontWeight: FontWeight.w600, - ), - ) - : null, - ), - title: Text( - name, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - subtitle: subtitle.isNotEmpty - ? Text( - subtitle, - style: TextStyle( - color: Colors.grey[600], - fontSize: 12, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ) - : null, - trailing: Icon( - Icons.chevron_right, - color: Colors.grey[400], - size: 20, - ), - onTap: () { - // TODO: Navigate to detail screen - }, - ); - } -} \ No newline at end of file diff --git a/lib/ui/screens/modern/dashboard_state.dart b/lib/ui/screens/modern/dashboard_state.dart deleted file mode 100644 index b7d4baf..0000000 --- a/lib/ui/screens/modern/dashboard_state.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:bottle_crm/model/account.dart'; -import 'package:bottle_crm/model/contact.dart'; -import 'package:bottle_crm/model/opportunities.dart'; - -@immutable -sealed class DashboardState {} - -class DashboardInitial extends DashboardState {} - -class DashboardLoading extends DashboardState {} - -class DashboardLoaded extends DashboardState { - final List accounts; - final List contacts; - final List opportunities; - final int accountsCount; - final int contactsCount; - final int leadsCount; - final int opportunitiesCount; - - DashboardLoaded({ - required this.accounts, - required this.contacts, - required this.opportunities, - required this.accountsCount, - required this.contactsCount, - required this.leadsCount, - required this.opportunitiesCount, - }); - - Map toMap() { - return { - 'accounts': accounts, - 'contacts': contacts, - 'opportunities': opportunities, - 'accountsCount': accountsCount, - 'contactsCount': contactsCount, - 'leadsCount': leadsCount, - 'opportunitiesCount': opportunitiesCount, - }; - } -} - -class DashboardError extends DashboardState { - final String message; - final Exception? exception; - - DashboardError(this.message, [this.exception]); -} - -class DashboardEmpty extends DashboardState {} \ No newline at end of file diff --git a/lib/ui/screens/more_options_screen.dart b/lib/ui/screens/more_options_screen.dart deleted file mode 100644 index 99cd87a..0000000 --- a/lib/ui/screens/more_options_screen.dart +++ /dev/null @@ -1,319 +0,0 @@ -import 'dart:core'; - -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class MoreOptions extends StatefulWidget { - @override - State createState() => _MoreOptionsState(); -} - -class _MoreOptionsState extends State { - final List _optionsList = [ - { - 'title': 'Contacts', - 'route': '/contacts_list', - 'icon': 'assets/images/contacts.svg' - }, - { - 'title': 'Opportunities', - 'route': '/opportunities_list', - 'icon': 'assets/images/opportunities.svg' - }, - { - 'title': 'Cases', - 'route': '/cases_list', - 'icon': 'assets/images/cases.svg' - }, - { - 'title': 'Documents', - 'route': '/documents_list', - 'icon': 'assets/images/documents.svg' - }, - { - 'title': 'Leads', - 'route': '/leads_list', - 'icon': 'assets/images/leads.svg' - }, - { - 'title': 'Invoices', - 'route': '/invoices_list', - 'icon': 'assets/images/invoices.svg' - }, - { - 'title': 'Events', - 'route': '/events_list', - 'icon': 'assets/images/events.svg' - }, - { - 'title': 'Teams', - 'route': '/teams_list', - 'icon': 'assets/images/teams.svg' - }, - { - 'title': 'Users', - 'route': '/users_list', - 'icon': 'assets/images/users.svg' - }, - { - 'title': 'Settings', - 'route': '/settings_List', - 'icon': 'assets/images/settings.svg' - }, - { - 'title': 'Change Password', - 'route': '/change_password', - 'icon': 'assets/images/change_password.svg' - }, - {'title': 'Logout', 'icon': 'assets/images/logout.svg'}, - ]; - - @override - void initState() { - super.initState(); - } - - void showLogoutAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Logout?", - style: TextStyle(color: Theme.of(context).secondaryHeaderColor), - ), - content: Text( - "Are you sure you want to logout?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - SharedPreferences prefs = - await SharedPreferences.getInstance(); - prefs.remove('authToken'); - prefs.remove('org'); - currentBottomNavigationIndex = "0"; - await FirebaseAnalytics.instance - .logEvent(name: "User_Logged_Out"); - Navigator.pushReplacementNamed(context, "/login"); - }, - child: Text("Logout")), - ], - ); - }); - } - - buildProfile() { - return Container( - padding: EdgeInsets.only(left: 20.0, right: 10.0), - height: screenHeight * 0.15, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - margin: EdgeInsets.only(right: 10.0), - child: authBloc.userProfile!.profileUrl != null && - authBloc.userProfile!.profileUrl != "" - ? CircleAvatar( - radius: screenWidth / 11.5, - backgroundColor: Theme.of(context).primaryColor, - child: CircleAvatar( - radius: screenWidth / 12, - backgroundImage: - NetworkImage(authBloc.userProfile!.profileUrl!), - backgroundColor: Colors.white, - ), - ) - : CircleAvatar( - radius: screenWidth / 12, - child: Text( - authBloc.userProfile!.firstName![0].allInCaps, - style: TextStyle( - fontSize: screenWidth / 11, - fontWeight: FontWeight.bold, - color: Theme.of(context).primaryColor), - ), - backgroundColor: Colors.grey[200], - ), - ), - Container( - width: screenWidth * 0.6, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - authBloc.userProfile!.firstName!.capitalizeFirstofEach(), - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500), - ), - SizedBox(height: 3.0), - Text( - authBloc.userProfile!.email!, - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 26, - fontWeight: FontWeight.w500), - ), - SizedBox(height: 3.0), - Text.rich(TextSpan(children: [ - TextSpan( - text: "Permissions: ", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 26, - fontWeight: FontWeight.w500)), - TextSpan( - text: authBloc.userProfile!.role!.toLowerCase() == - "admin" - ? 'Sales and Marketing' - : authBloc.userProfile!.hasSalesAccess! && - authBloc.userProfile!.hasMarketingAccess! - ? "Sales and Marketing" - : authBloc.userProfile!.hasSalesAccess! && - !authBloc - .userProfile!.hasMarketingAccess! - ? "Sales" - : !authBloc.userProfile! - .hasSalesAccess! && - authBloc.userProfile! - .hasMarketingAccess! - ? "Marketing" - : "---", - style: TextStyle( - color: Colors.green, - fontSize: screenWidth / 26, - fontWeight: FontWeight.w500)) - ])) - ], - ), - ), - Container( - child: IconButton( - onPressed: () { - Navigator.pushNamed(context, '/profile'); - }, - icon: Icon(Icons.arrow_forward_ios, - color: Colors.white, size: screenWidth / 15)), - ) - ], - ), - )); - } - - buildOptions() { - return Container( - padding: EdgeInsets.symmetric(vertical: 10.0), - child: ListView.builder( - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: _optionsList.length, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - if (_optionsList[index]['title'] == "Logout") { - showLogoutAlertDialog(context); - } else { - Navigator.pushNamed(context, _optionsList[index]['route']); - } - }, - child: Column( - children: [ - Container( - child: Row( - children: [ - Container( - padding: - EdgeInsets.fromLTRB(screenWidth / 12, 8, 20, 8), - child: SvgPicture.asset( - _optionsList[index]['icon'], - width: screenWidth / 18, - ), - ), - Container( - child: Text( - _optionsList[index]['title'], - style: TextStyle( - color: _optionsList[index]['title'] == "Logout" - ? Colors.red - : Color.fromRGBO(75, 75, 78, 1), - fontSize: screenWidth / 24, - fontWeight: FontWeight.w500), - ), - ) - ], - ), - ), - index == _optionsList.length - 1 - ? Container() - : Container( - padding: EdgeInsets.symmetric(horizontal: 20.0), - child: Divider(color: Colors.grey[200])) - ], - ), - ); - }, - ), - ); - } - - @override - Widget build(BuildContext context) { - return PopScope( - canPop: true, - child: Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Text( - 'More Options', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ), - buildProfile(), - Expanded( - child: Container( - color: Colors.white, - child: buildOptions(), - )) - ], - ), - ), - ), - bottomNavigationBar: BottomNavigationBarWidget(), - ), - ); - } -} diff --git a/lib/ui/screens/opportunities/opportunitie_create.dart b/lib/ui/screens/opportunities/opportunitie_create.dart deleted file mode 100644 index 5e61094..0000000 --- a/lib/ui/screens/opportunities/opportunitie_create.dart +++ /dev/null @@ -1,1024 +0,0 @@ -import 'dart:io'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -//import 'package:textfield_tags/textfield_tags.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; - -class CreateOpportunities extends StatefulWidget { - CreateOpportunities(); - @override - State createState() => _CreateOpportunitiesState(); -} - -class _CreateOpportunitiesState extends State { - quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _opportunityFormKey = GlobalKey(); - TextEditingController _dateController = TextEditingController(); - TextEditingController fileNameController = new TextEditingController(); - String? selectedDate = ""; - DateTime? initialDate = DateTime.now(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File file = new File(''); - List _opportunityFormKeys = [ - "name", - "account", - "amount", - "contacts", - "currency", - "stage", - "lead_source", - "probability", - "assigned_to", - "contacts", - "due_date", - "tags", - "opportunity_attachment" - "teams" - ]; - - @override - void initState() { - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - super.initState(); - } - - _selectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate!, - firstDate: DateTime(1950), - lastDate: DateTime(2023), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_opportunityFormKey.currentState != null) - _opportunityFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: buildOpportunityBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildDescriptionBlock()); - } - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildOpportunityBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _opportunityFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: opportunityBloc - .currentEditOpportunity['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - opportunityBloc - .currentEditOpportunity['name'] = value; - }, - ), - ), - _errors['name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Lead Source ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.leadSourceObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc.currentEditOpportunity[ - 'lead_source'] = ""; - } else { - opportunityBloc.currentEditOpportunity[ - 'lead_source'] = selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['lead_source'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Lead Source", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Account", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.accountsObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc - .currentEditOpportunity['account'] = ""; - } else { - opportunityBloc - .currentEditOpportunity['account'] = - selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['account'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Lead Source", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Probability ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - maxLength: 2, - initialValue: opportunityBloc - .currentEditOpportunity['probability'] - .toString(), - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - onSaved: (value) { - opportunityBloc.currentEditOpportunity[ - 'probability'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Amount ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: opportunityBloc - .currentEditOpportunity['amount'] - .toString(), - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - onSaved: (value) { - opportunityBloc - .currentEditOpportunity['amount'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: opportunityBloc - .currentEditOpportunity['teams'], - onSaved: (value) { - if (value == null) return; - opportunityBloc - .currentEditOpportunity['teams'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Currency", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.currencyObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc.currentEditOpportunity[ - 'currency'] = ""; - } else { - opportunityBloc.currentEditOpportunity[ - 'currency'] = selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['currency'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Currency", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Stage ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.stageObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc - .currentEditOpportunity['stage'] = ""; - } else { - opportunityBloc - .currentEditOpportunity['stage'] = - selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['stage'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Stage", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned to", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Users", - ), - initialValue: opportunityBloc - .currentEditOpportunity['assigned_to'], - onSaved: (value) { - if (value == null) return; - opportunityBloc.currentEditOpportunity[ - 'assigned_to'] = value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Contacts ', - style: buildLableTextStyle(), - children: [ - TextSpan( - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: opportunityBloc - .currentEditOpportunity['contacts'], - onSaved: (value) { - if (value == null) return; - opportunityBloc - .currentEditOpportunity['contacts'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Due Date ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _dateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _selectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - // keyboardType: TextInputType.text - ), - ), - ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Tags", - // style: buildLableTextStyle(), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // margin: EdgeInsets.only(bottom: 5.0), - // child: TextFieldTags( - // initialTags: opportunityBloc.tags, - // textFieldStyler: TextFieldStyler( - // textFieldBorder: boxBorder(), - // textFieldFocusedBorder: boxBorder(), - // hintText: 'Enter Tags', - // hintStyle: TextStyle(fontSize: 16.0), - // helperText: "", - // ), - // tagsStyler: TagsStyler( - // tagTextPadding: - // EdgeInsets.symmetric(horizontal: 5.0), - // tagDecoration: BoxDecoration( - // color: Colors.lightGreen[300], - // borderRadius: BorderRadius.circular(0.0), - // ), - // tagCancelIcon: Icon(Icons.cancel, - // size: 18.0, color: Colors.green[900]), - // tagPadding: const EdgeInsets.all(6.0)), - // onTag: (tag) { - // setState(() { - // opportunityBloc - // .currentEditOpportunity['tags'] - // .add(tag); - // }); - // }, - // onDelete: (tag) { - // setState(() { - // opportunityBloc - // .currentEditOpportunity['tags'] - // .remove(tag); - // }); - // }, - // ), - // ), - // ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - quill.QuillSimpleToolbar( - controller: _controller, - config: const quill.QuillSimpleToolbarConfig(), - ), - Expanded( - child: Container( - child: quill.QuillEditor.basic( - controller: _controller, - config: const quill.QuillEditorConfig()), - ), - ) - ], - )); - } - - @override - Widget build(BuildContext context) { - // Set readOnly property based on loading state - _controller.readOnly = _isLoading; - - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - dashboardBloc.fetchDashboardDetails(); - opportunityBloc.cancelCurrentEditOpportunity(); - opportunityBloc.currentEditOpportunityId = ""; - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - opportunityBloc.currentEditOpportunityId == "" - ? 'Add Opportunity' - : "Edit Opportunity", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_opportunityFormKey.currentState != null) - _opportunityFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - // opportunityBloc.currentEditOpportunity['description'] = - // _controller.document.toPlainText(); - print(opportunityBloc - .currentEditOpportunity['description']); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Opportunity', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_opportunityFormKey.currentState != null) - _opportunityFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_opportunityFormKey.currentState != null) { - if (!_opportunityFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _opportunityFormKey.currentState!.save(); - await Future.delayed(const Duration(seconds: 1), () async {}); - - Map _result = {}; - if (opportunityBloc.currentEditOpportunityId != null && - opportunityBloc.currentEditOpportunityId != "") { - _result = await opportunityBloc.editOpportunity(); - } else { - _result = await opportunityBloc.createOpportunity(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - opportunityBloc.cancelCurrentEditOpportunity(); - opportunityBloc.currentEditOpportunityId = ""; - showToaster(_result['message'], context); - opportunityBloc.opportunities.clear(); - opportunityBloc.offset = ""; - await opportunityBloc.fetchOpportunities(); - opportunityBloc.opportunities; - await FirebaseAnalytics.instance.logEvent(name: "Opportunity_Created"); - Navigator.pushReplacementNamed(context, '/opportunities_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _opportunityFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/opportunities/opportunitie_create.dart.bak b/lib/ui/screens/opportunities/opportunitie_create.dart.bak deleted file mode 100644 index 223addf..0000000 --- a/lib/ui/screens/opportunities/opportunitie_create.dart.bak +++ /dev/null @@ -1,1024 +0,0 @@ -import 'dart:io'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -//import 'package:textfield_tags/textfield_tags.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; - -class CreateOpportunities extends StatefulWidget { - CreateOpportunities(); - @override - State createState() => _CreateOpportunitiesState(); -} - -class _CreateOpportunitiesState extends State { - quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _opportunityFormKey = GlobalKey(); - TextEditingController _dateController = TextEditingController(); - TextEditingController fileNameController = new TextEditingController(); - String? selectedDate = ""; - DateTime? initialDate = DateTime.now(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File file = new File(''); - List _opportunityFormKeys = [ - "name", - "account", - "amount", - "contacts", - "currency", - "stage", - "lead_source", - "probability", - "assigned_to", - "contacts", - "due_date", - "tags", - "opportunity_attachment" - "teams" - ]; - - @override - void initState() { - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - super.initState(); - } - - _selectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate!, - firstDate: DateTime(1950), - lastDate: DateTime(2023), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - if (_opportunityFormKey.currentState != null) - _opportunityFormKey.currentState!.save(); - _currentTabIndex = 1; - }); - }, - child: buildOpportunityBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildDescriptionBlock()); - } - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildOpportunityBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _opportunityFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: opportunityBloc - .currentEditOpportunity['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - opportunityBloc - .currentEditOpportunity['name'] = value; - }, - ), - ), - _errors['name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Lead Source ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.leadSourceObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc.currentEditOpportunity[ - 'lead_source'] = ""; - } else { - opportunityBloc.currentEditOpportunity[ - 'lead_source'] = selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['lead_source'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Lead Source", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Account", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => opportunityBloc.accountsObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc - .currentEditOpportunity['account'] = ""; - } else { - opportunityBloc - .currentEditOpportunity['account'] = - selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['account'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Lead Source", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Probability ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - maxLength: 2, - initialValue: opportunityBloc - .currentEditOpportunity['probability'] - .toString(), - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - onSaved: (value) { - opportunityBloc.currentEditOpportunity[ - 'probability'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Amount ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: opportunityBloc - .currentEditOpportunity['amount'] - .toString(), - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - onSaved: (value) { - opportunityBloc - .currentEditOpportunity['amount'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: opportunityBloc - .currentEditOpportunity['teams'], - onSaved: (value) { - if (value == null) return; - opportunityBloc - .currentEditOpportunity['teams'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Currency", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: opportunityBloc.currencyObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc.currentEditOpportunity[ - 'currency'] = ""; - } else { - opportunityBloc.currentEditOpportunity[ - 'currency'] = selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['currency'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Currency", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Stage ', - style: buildLableTextStyle(), - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: opportunityBloc.stageObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - opportunityBloc - .currentEditOpportunity['stage'] = ""; - } else { - opportunityBloc - .currentEditOpportunity['stage'] = - selection; - } - }, - selectedItem: opportunityBloc - .currentEditOpportunity['stage'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Stage", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned to", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Users", - ), - initialValue: opportunityBloc - .currentEditOpportunity['assigned_to'], - onSaved: (value) { - if (value == null) return; - opportunityBloc.currentEditOpportunity[ - 'assigned_to'] = value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Contacts ', - style: buildLableTextStyle(), - children: [ - TextSpan( - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: opportunityBloc - .currentEditOpportunity['contacts'], - onSaved: (value) { - if (value == null) return; - opportunityBloc - .currentEditOpportunity['contacts'] = - value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Due Date ", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _dateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _selectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - // keyboardType: TextInputType.text - ), - ), - ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Tags", - // style: buildLableTextStyle(), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // margin: EdgeInsets.only(bottom: 5.0), - // child: TextFieldTags( - // initialTags: opportunityBloc.tags, - // textFieldStyler: TextFieldStyler( - // textFieldBorder: boxBorder(), - // textFieldFocusedBorder: boxBorder(), - // hintText: 'Enter Tags', - // hintStyle: TextStyle(fontSize: 16.0), - // helperText: "", - // ), - // tagsStyler: TagsStyler( - // tagTextPadding: - // EdgeInsets.symmetric(horizontal: 5.0), - // tagDecoration: BoxDecoration( - // color: Colors.lightGreen[300], - // borderRadius: BorderRadius.circular(0.0), - // ), - // tagCancelIcon: Icon(Icons.cancel, - // size: 18.0, color: Colors.green[900]), - // tagPadding: const EdgeInsets.all(6.0)), - // onTag: (tag) { - // setState(() { - // opportunityBloc - // .currentEditOpportunity['tags'] - // .add(tag); - // }); - // }, - // onDelete: (tag) { - // setState(() { - // opportunityBloc - // .currentEditOpportunity['tags'] - // .remove(tag); - // }); - // }, - // ), - // ), - // ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - quill.QuillSimpleToolbar( - controller: _controller, - config: const quill.QuillSimpleToolbarConfig(), - ), - Expanded( - child: Container( - child: quill.QuillEditor.basic( - controller: _controller, - config: const quill.QuillEditorConfig()), - ), - ) - ], - )); - } - - @override - Widget build(BuildContext context) { - // Set readOnly property based on loading state - _controller.readOnly = _isLoading; - - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - dashboardBloc.fetchDashboardDetails(); - opportunityBloc.cancelCurrentEditOpportunity(); - opportunityBloc.currentEditOpportunityId = ""; - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - opportunityBloc.currentEditOpportunityId == "" - ? 'Add Opportunity' - : "Edit Opportunity", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_opportunityFormKey.currentState != null) - _opportunityFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - // opportunityBloc.currentEditOpportunity['description'] = - // _controller.document.toPlainText(); - print(opportunityBloc - .currentEditOpportunity['description']); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Opportunity', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_opportunityFormKey.currentState != null) - _opportunityFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ) - : Container(), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_opportunityFormKey.currentState != null) { - if (!_opportunityFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _opportunityFormKey.currentState!.save(); - await Future.delayed(const Duration(seconds: 1), () async {}); - - Map _result = {}; - if (opportunityBloc.currentEditOpportunityId != null && - opportunityBloc.currentEditOpportunityId != "") { - _result = await opportunityBloc.editOpportunity(); - } else { - _result = await opportunityBloc.createOpportunity(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - opportunityBloc.cancelCurrentEditOpportunity(); - opportunityBloc.currentEditOpportunityId = ""; - showToaster(_result['message'], context); - opportunityBloc.opportunities.clear(); - opportunityBloc.offset = ""; - await opportunityBloc.fetchOpportunities(); - opportunityBloc.opportunities; - await FirebaseAnalytics.instance.logEvent(name: "Opportunity_Created"); - Navigator.pushReplacementNamed(context, '/opportunities_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _opportunityFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/opportunities/opportunitie_details.dart b/lib/ui/screens/opportunities/opportunitie_details.dart deleted file mode 100644 index 24226e3..0000000 --- a/lib/ui/screens/opportunities/opportunitie_details.dart +++ /dev/null @@ -1,839 +0,0 @@ -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/model/opportunities.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class OpportunitiesDetails extends StatefulWidget { - OpportunitiesDetails(); - @override - State createState() => _OpportunitiesDetailsState(); -} - -class _OpportunitiesDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Opportunity Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - opportunityBloc.currentEditOpportunityId = - opportunityBloc.currentOpportunity!.id - .toString(); - await opportunityBloc - .updateCurrentEditOpportunity( - opportunityBloc.currentOpportunity!); - Navigator.pushNamed( - context, '/opportunitie_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - !_isLoading - ? Container( - child: Column( - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 - ? 3.0 - : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Opportunity Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 28, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 - ? 3.0 - : 0.0, - ))), - width: screenWidth * 0.24, - child: Text( - 'Attachments', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 2 - ? 3.0 - : 0.0, - ))), - width: screenWidth * 0.21, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - )), - ], - ), - ) - : Container(), - Expanded( - child: Container( - child: !_isLoading - ? buildTopBar() - : Container(color: Colors.white), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ])); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildOpportunityInfoBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildAttachmentBlock()); - } else if (_currentTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildDescriptionBlock()); - } - } - - buildAttachmentBlock() { - return Container( - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - color: Colors.white, - child: Text("No Attachment Found..."), - ); - } - - buildDescriptionBlock() { - return Container( - alignment: Alignment.center, - height: screenHeight, - width: screenWidth, - color: Colors.white, - child: Text( - opportunityBloc.currentOpportunity!.description != "" - ? opportunityBloc.currentOpportunity!.description! - : "No Description Found", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22.0)), - ); - } - - buildOpportunityInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Text( - opportunityBloc.currentOpportunity!.name!.allInCaps, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - opportunityBloc.currentOpportunity!.amount != "" - ? Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: ColorBrightness.dark), - child: Text( - opportunityBloc.currentOpportunity!.amount!, - style: TextStyle(color: Colors.white, fontSize: 15.0), - ), - ) - : Container(), - SizedBox(height: 10.0), - TagViewWidget(opportunityBloc.currentOpportunity!.tags!), - SizedBox(height: 10.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: ProfilePicViewWidget(opportunityBloc - .currentOpportunity!.assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser.firstName![0].inCaps - : assignedUser.profileUrl) - .toList()) - ), - ], - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Account :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.account!.name == - null - ? "-----" - : opportunityBloc - .currentOpportunity!.account!.name!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Status :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.stage!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Closed Date :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.dueDate == null - ? "-----" - : opportunityBloc.currentOpportunity!.closedOn - .toString(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - )), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Lead Souece :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.leadSource!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Amount :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - opportunityBloc.currentOpportunity!.amount!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - SizedBox(width: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc - .currentOpportunity!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${opportunityBloc.currentOpportunity!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(width: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - " +91 0000 000 000", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 10.0), - Text( - " +91 0000 000 000", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Teams :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.teams!.length == 0 - ? "-----" - : _getTeams(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "User :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - alignment: Alignment.centerLeft, - width: screenWidth * 0.50, - child: Text( - opportunityBloc - .currentOpportunity!.assignedTo!.length == - 0 - ? "-----" - : _getUsers(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )) - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Probability :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - alignment: Alignment.centerLeft, - width: screenWidth * 0.50, - child: Text( - opportunityBloc.currentOpportunity!.probability! - .toString() == - "" - ? "-----" - : opportunityBloc.currentOpportunity!.probability! - .toString(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )) - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteOpportunityAlertDialog( - context, opportunityBloc.currentOpportunity!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))); - } - - _getTeams() { - List teams = []; - - opportunityBloc.currentOpportunity!.teams!.forEach((_teams) { - String _teamsList; - _teamsList = _teams.name!; - teams.add(_teamsList); - }); - - return teams.toString().replaceAll("[", "").replaceAll("]", ""); - } - - _getUsers() { - List users = []; - - opportunityBloc.currentOpportunity!.assignedTo!.forEach((_teams) { - String _teamsList; - _teamsList = _teams.firstName!; - users.add(_teamsList); - }); - - return users.toString().replaceAll("[", "").replaceAll("]", ""); - } - - void showDeleteOpportunityAlertDialog( - BuildContext context, Opportunity opportunity) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - opportunity.name != "" - ? opportunity.name!.capitalizeFirstofEach() - : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this Opportunity?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteOpportunity(opportunity); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteOpportunity(Opportunity opportunity) async { - setState(() { - _isLoading = true; - }); - Map result = await opportunityBloc.deleteOpportunity(opportunity); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - opportunityBloc.opportunities.clear(); - opportunityBloc.fetchOpportunities(); - await FirebaseAnalytics.instance.logEvent(name: "Opportunity_Deleted"); - Navigator.pushNamedAndRemoveUntil( - context, '/opportunities_list', ((route) => false)); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, result['message'].toString(), opportunity); - } - } - - showErrorMessage(BuildContext context, msg, Opportunity opportunity) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteOpportunity(opportunity); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/opportunities/opportunities_list.dart b/lib/ui/screens/opportunities/opportunities_list.dart deleted file mode 100644 index cddc6c2..0000000 --- a/lib/ui/screens/opportunities/opportunities_list.dart +++ /dev/null @@ -1,780 +0,0 @@ -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/model/opportunities.dart'; -import 'package:bottle_crm/model/profile.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -//import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; - -class OpportunitiesList extends StatefulWidget { - OpportunitiesList(); - @override - State createState() => _OpportunitiesListState(); -} - -class _OpportunitiesListState extends State { - final GlobalKey _filtersFormKey = GlobalKey(); - bool _isFilter = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - List? _assignedUsers = []; - List _opportunities = []; - Map _filtersFormData = { - "name": "", - "account": "", - "stage": "", - "lead_source": "", - "tags": [] - }; - bool _isLoading = false; - - @override - void initState() { - setState(() { - _opportunities = opportunityBloc.opportunities; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - opportunityBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await opportunityBloc.fetchOpportunities( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - _getUsers(); - super.initState(); - } - - _getUsers() { - _opportunities.forEach((element) { - _assignedUsers!.addAll(element.assignedTo!); - }); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - opportunityBloc.offset = ""; - opportunityBloc.opportunities.clear(); - await opportunityBloc.fetchOpportunities( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter Name", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['name'] = value; - }, - ), - ), - SizedBox(height: 10.0), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Stage", - // style: buildLableTextStyle(), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // height: 48.0, - // margin: EdgeInsets.only(bottom: 5.0), - // child: DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: opportunityBloc.stageObjforDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // opportunityBloc - // .currentEditOpportunity['stage'] = ""; - // } else { - // opportunityBloc - // .currentEditOpportunity['stage'] = - // selection; - // } - // }, - // selectedItem: opportunityBloc - // .currentEditOpportunity['stage'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Stage", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Stage', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ) - // ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Account", - // style: buildLableTextStyle(), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // height: 48.0, - // margin: EdgeInsets.only(bottom: 5.0), - // child: DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: opportunityBloc.accountsObjforDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // opportunityBloc - // .currentEditOpportunity['account'] = ""; - // } else { - // opportunityBloc - // .currentEditOpportunity['account'] = - // selection; - // } - // }, - // selectedItem: opportunityBloc - // .currentEditOpportunity['account'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Account", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Account', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ) - // ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Lead Source", - // style: buildLableTextStyle(), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // height: 48.0, - // margin: EdgeInsets.only(bottom: 5.0), - // child: DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: opportunityBloc.leadSourceObjforDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // opportunityBloc.currentEditOpportunity[ - // 'lead_source'] = ""; - // } else { - // opportunityBloc.currentEditOpportunity[ - // 'lead_source'] = selection; - // } - // }, - // selectedItem: opportunityBloc - // .currentEditOpportunity['lead_source'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Lead Source", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Lead source', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ) - // ])), - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - margin: EdgeInsets.only(bottom: 5.0), - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: opportunityBloc.filtertags, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text("Tags"), - initialValue: _filtersFormData['tags'], - onSaved: (value) { - if (value == null) return; - _filtersFormData['tags'] = value; - }, - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "name": "", - "account": "", - "stage": "", - "lead_source": "", - "tags": [] - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - Widget _buildopportunitiesList() { - return _opportunities.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _opportunities.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - opportunityBloc.currentOpportunity = - _opportunities[index]; - Navigator.pushNamed(context, '/opportunitie_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - child: Text( - _opportunities[index] - .name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 22), - ), - ), - ], - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - // _opportunities[index].assignedTo!.length != 0 - // ? Container( - // child: Row( - // children: [ - // _opportunities[index] - // .assignedTo![0] - // .profileUrl != - // "" - // ? CircleAvatar( - // radius: screenWidth / 25, - // backgroundImage: - // NetworkImage( - // _opportunities[ - // index] - // .assignedTo![ - // 0] - // .profileUrl!), - // ) - // : CircleAvatar( - // radius: screenWidth / 25, - // backgroundColor: - // randomColor.randomColor( - // colorBrightness: - // ColorBrightness - // .light), - // child: Text( - // _opportunities[index] - // .assignedTo![0] - // .firstName![0] - // .toUpperCase(), - // style: TextStyle( - // color: Colors.white, - // fontWeight: - // FontWeight - // .bold), - // ), - // ), - // SizedBox(width: 3.0), - // _opportunities[index] - // .assignedTo![0] - // .profileUrl != - // ""&&_opportunities[index].assignedTo!.length<=2 - // ? CircleAvatar( - // radius: screenWidth / 25, - // backgroundImage: - // NetworkImage( - // _opportunities[ - // index] - // .assignedTo![ - // 1] - // .profileUrl!), - // ) - // : CircleAvatar( - // radius: screenWidth / 25, - // backgroundColor: - // randomColor.randomColor( - // colorBrightness: - // ColorBrightness - // .light), - // child: Text( - // _opportunities[index] - // .assignedTo![1] - // .firstName![0] - // .toUpperCase(), - // style: TextStyle( - // color: Colors.white, - // fontWeight: - // FontWeight - // .bold), - // ), - // ), - // SizedBox(width: 3.0), - // CircleAvatar( - // radius: screenWidth / 25, - // backgroundColor: Colors.grey, - // child: Text( - // "JR", - // style: TextStyle( - // color: Colors.white, - // fontWeight: - // FontWeight.bold), - // ), - // ), - // ], - // ), - // ) - // : Container(), - ProfilePicViewWidget(_opportunities[index] - .assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser - .firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - Row( - children: [ - _opportunities[index].stage != "" - ? Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, - vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: - ColorBrightness.light), - child: Text( - _opportunities[index].stage!, - style: TextStyle( - color: Colors.white, - fontSize: 12.0), - ), - ) - : Container(), - SizedBox(width: 10.0), - Container( - child: Text( - _opportunities[index].amount == "" - ? "₹0" - : "₹" + - _opportunities[index] - .amount!, - style: TextStyle( - color: Theme.of(context) - .primaryColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w600)), - ) - ], - ), - ], - ), - ), - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Opportunitis Found.'), - ); - } - - - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - currentBottomNavigationIndex == "4" - ? Navigator.pushReplacementNamed( - context, "/dashboard") - : Navigator.pushReplacementNamed( - context, "/more_options"); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Opportunities', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, - child: _buildopportunitiesList(), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - opportunityBloc.currentEditOpportunityId = ""; - if (opportunityBloc.opportunities.length == 0) { - showAlertDialog(context); - } else { - Navigator.pushNamed(context, '/opportunitie_create'); - } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any opportunity, Please create opportunity first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/opportunitie_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/settings/settings.dart b/lib/ui/screens/settings/settings.dart deleted file mode 100644 index 1ac0a4c..0000000 --- a/lib/ui/screens/settings/settings.dart +++ /dev/null @@ -1,424 +0,0 @@ -import 'package:bottle_crm/bloc/setting_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:bottle_crm/model/user.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/model/settings.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class SettingsList extends StatefulWidget { - SettingsList(); - @override - State createState() => _SettingsListState(); -} - -class _SettingsListState extends State { - var _currentTabIndex = 0; - - List _settings = []; - List _users = []; - - bool _isLoading = false; - bool _isNextPageLoading = false; - ScrollController? scrollController; - - @override - void initState() { - setState(() { - _settings = settingsBloc.apiSettings; - _users = settingsBloc.usersList; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - settingsBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: _buildSettingsList()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: _buildUsersBlock()); - } - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row(children: [ - GestureDetector( - onTap: () { - Navigator.pop(context); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, size: screenWidth / 18)), - Text( - 'Settings', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - if (_currentTabIndex != 0) { - setState(() { - _currentTabIndex = 0; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Api Settings', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - if (_currentTabIndex != 1) { - setState(() { - _currentTabIndex = 1; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Users', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ) - ], - ), - ), - ], - ), - ), - Expanded( - child: Container(color: Colors.white, child: buildTopBar()), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - Widget _buildSettingsList() { - return _settings.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _settings.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - settingsBloc.currentSettings = _settings[index]; - Navigator.pushNamed(context, '/settings_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _settings[index] - .title! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Container( - width: screenWidth * 0.3, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - _settings[index] - .createdBy! - .profileUrl != - "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _settings[index] - .createdBy! - .profileUrl!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context) - .primaryColor, - child: Text( - _settings[index] - .createdBy! - .firstName![0] - .allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: - FontWeight.bold), - ), - ), - SizedBox(width: 5.0), - Text( - _settings[index] - .createdBy! - .firstName! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w500, - fontSize: screenWidth / 25)) - ], - ), - ) - ], - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.5, - child: TagViewWidget( - _settings[index].tags!)), - Text(_settings[index].createdOn!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ) - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Api Settings Found.'), - ); - } - - Widget _buildUsersBlock() { - return _users.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _users.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - userBloc.currentUser = _users[index]; - Navigator.pushNamed(context, '/user_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - children: [ - _users[index].profilePic != "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _users[index].profilePic!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context).primaryColor, - child: Text( - _users[index] - .firstName![0] - .allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ), - SizedBox(width: 10.0), - Column( - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _users[index] - .firstName! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Container( - width: screenWidth * 0.55, - child: Text(_users[index].role!, - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.grey, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 30)), - ), - ], - ), - ], - ), - ), - SizedBox(height: 5.0), - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Users Found.'), - ); - } -} diff --git a/lib/ui/screens/settings/settings_details.dart b/lib/ui/screens/settings/settings_details.dart deleted file mode 100644 index 9ed7b87..0000000 --- a/lib/ui/screens/settings/settings_details.dart +++ /dev/null @@ -1,498 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/setting_bloc.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class SettingsDeails extends StatefulWidget { - SettingsDeails(); - @override - State createState() => _SettingsDeailsState(); -} - -class _SettingsDeailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Settings Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - // GestureDetector( - // onTap: () async { - - // }, - // child: Container( - // decoration: BoxDecoration( - // borderRadius: - // BorderRadius.all(Radius.circular(3.0)), - // color: Colors.white, - // ), - // width: screenWidth * 0.18, - // height: screenHeight * 0.04, - // alignment: Alignment.center, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceEvenly, - // children: [ - // SvgPicture.asset( - // 'assets/images/Icon_edit_color.svg', - // color: Theme.of(context).primaryColor, - // width: screenWidth / 25, - // ), - // Container( - // child: Text( - // "Edit", - // style: TextStyle( - // fontSize: screenWidth / 25, - // color: Theme.of(context).primaryColor, - // fontWeight: FontWeight.w500), - // ), - // ), - // ], - // ), - // ), - // ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Team Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - child: buildteamInfoBlock(), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildteamInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - settingsBloc.currentSettings!.title!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - SizedBox(height: 10.0), - TagViewWidget(settingsBloc.currentSettings!.tags!), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Create Date :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - settingsBloc.currentSettings!.createdOn!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Closed on :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Status :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - ], - )), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - settingsBloc.currentSettings!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${settingsBloc.currentSettings!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: - Icon(Icons.email_outlined, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "settings@mp.com", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "------------", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - // GestureDetector( - // onTap: () { - // if (!_isLoading) - // showDeleteteamAlertDialog(context, settingsBloc.currentTeam!); - // }, - // child: Container( - // padding: EdgeInsets.all(8.0), - // decoration: BoxDecoration( - // border: Border.all(width: 1.0, color: Colors.red.shade100), - // borderRadius: BorderRadius.all(Radius.circular(3.0)), - // color: Colors.white, - // ), - // width: screenWidth * 0.25, - // alignment: Alignment.center, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // SvgPicture.asset( - // 'assets/images/icon_delete_color.svg', - // width: screenWidth / 25, - // ), - // SizedBox(width: 10.0), - // Container( - // child: Text( - // "Delete", - // style: TextStyle( - // fontSize: screenWidth / 23, - // color: Colors.red, - // fontWeight: FontWeight.w500), - // ), - // ), - // ], - // ), - // ), - // ) - ]))); - } - - // void showDeleteteamAlertDialog(BuildContext context, Settings settings) { - // showDialog( - // context: context, - // builder: (BuildContext context) { - // return CupertinoAlertDialog( - // title: Text( - // settings.title!.capitalizeFirstofEach(), - // style: TextStyle(color: Colors.black), - // ), - // content: Text( - // "Are you sure you want to delete this team?", - // style: TextStyle(fontSize: 15.0), - // ), - // actions: [ - // CupertinoDialogAction( - // isDefaultAction: true, - // onPressed: () { - // Navigator.pop(context); - // }, - // child: Text("Cancel")), - // CupertinoDialogAction( - // textStyle: TextStyle(color: Colors.red), - // isDefaultAction: true, - // onPressed: () async { - // Navigator.pop(context); - // deleteSettings(settings); - // }, - // child: Text("Delete")), - // ], - // ); - // }); - // } - - // deleteSettings(Settings settings) async { - // setState(() { - // _isLoading = true; - // }); - // Map result = await settingsBloc.deleteTeam(team); - // setState(() { - // _isLoading = false; - // }); - // if (result['error'] == false) { - // showToaster(result['message'], context); - // teamBloc.teams.clear(); - // await teamBloc.fetchTeams(); - // await FirebaseAnalytics.instance.logEvent(name: "team_Deleted"); - // Navigator.pushReplacementNamed(context, '/teams_list'); - // } else if (result['error'] == true) { - // showToaster(result['message'], context); - // } else { - // showErrorMessage(context, result['message'].toString(), team); - // } - // } - - // showErrorMessage(BuildContext context, msg, Team team) { - // return showDialog( - // context: context, - // builder: (_) => AlertDialog( - // title: Text('Alert'), - // content: Text(msg), - // actions: [ - // TextButton( - // onPressed: () { - // Navigator.pop(context); - // deleteTeam(team); - // }, - // child: Text('RETRY')) - // ], - // )); - // } -} diff --git a/lib/ui/screens/settings/settings_userDetails.dart b/lib/ui/screens/settings/settings_userDetails.dart deleted file mode 100644 index b0618cb..0000000 --- a/lib/ui/screens/settings/settings_userDetails.dart +++ /dev/null @@ -1,512 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class SettingsUserDetails extends StatefulWidget { - SettingsUserDetails(); - @override - State createState() => _SettingsUserDetailsState(); -} - -class _SettingsUserDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'User Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - // GestureDetector( - // onTap: () async { - // if (!_isLoading) { - // userBloc.currentEditUserId = - // userBloc.currentUser!.id.toString(); - // await userBloc - // .updateCurrentEditUser(userBloc.currentUser!); - // Navigator.pushNamed(context, '/user_create'); - // } - // }, - // child: Container( - // decoration: BoxDecoration( - // borderRadius: - // BorderRadius.all(Radius.circular(3.0)), - // color: Colors.white, - // ), - // width: screenWidth * 0.18, - // height: screenHeight * 0.04, - // alignment: Alignment.center, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceEvenly, - // children: [ - // SvgPicture.asset( - // 'assets/images/Icon_edit_color.svg', - // color: Theme.of(context).primaryColor, - // width: screenWidth / 25, - // ), - // Container( - // child: Text( - // "Edit", - // style: TextStyle( - // fontSize: screenWidth / 25, - // color: Theme.of(context).primaryColor, - // fontWeight: FontWeight.w500), - // ), - // ), - // ], - // ), - // ), - // ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'User Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - child: buildTopBar(), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildUserInfoBlock(); - } else if (_currentTabIndex == 1) { - return buildDescriptionBlock(); - } - } - - buildDescriptionBlock() { - return Container( - child: Center( - child: Text("No Notes Found."), - ), - ); - } - - buildUserInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "First Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.firstName! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Last Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.lastName! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Role :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.role! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 5.0), - Text( - "https//:www.micropyramid.com", - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 25), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: - Icon(Icons.email_outlined, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.email!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.phone!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Image.asset( - "assets/images/skype.png", - width: screenWidth / 22, - )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Text( - // " skype@Id", - // style: TextStyle( - // color: Colors.blue, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - ], - ), - ], - ), - ), - SizedBox(height: 10), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column(children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Address :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "${userBloc.currentUser!.adressLine} ${userBloc.currentUser!.street!}, ${userBloc.currentUser!.city!}, ${userBloc.currentUser!.state!}, ${userBloc.currentUser!.country!}, ${userBloc.currentUser!.pincode!}.", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ])), - SizedBox(height: 10.0), - ]))); - } -} diff --git a/lib/ui/screens/tasks/task_create.dart b/lib/ui/screens/tasks/task_create.dart deleted file mode 100644 index a33ff19..0000000 --- a/lib/ui/screens/tasks/task_create.dart +++ /dev/null @@ -1,867 +0,0 @@ -import 'dart:io'; - -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/task_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:dropdown_search/dropdown_search.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; - -import 'package:bottle_crm/utils/utils.dart'; -import 'package:intl/intl.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; - -class CreateTask extends StatefulWidget { - CreateTask(); - @override - State createState() => _CreateTaskState(); -} - -class _CreateTaskState extends State { - final GlobalKey _taskFormKey = GlobalKey(); - TextEditingController _dateController = TextEditingController(); - TextEditingController fileNameController = new TextEditingController(); - String? selectedDate = ""; - DateTime initialDate = DateTime.now(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File? file = File(''); - List _taskFormKeys = [ - 'title', - 'status', - 'priority', - 'account', - 'contacts', - 'closed_on', - 'assigned_to', - 'teams', - ]; - - @override - void initState() { - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(DateTime.now().toString())); - super.initState(); - } - - _selectDate(BuildContext context) async { - final DateTime? selected = await showDatePicker( - context: context, - initialDate: initialDate, - firstDate: DateTime(1950), - lastDate: DateTime(2023), - ); - if (selected != null && selected.toString() != selectedDate) - setState(() { - initialDate = selected; - selectedDate = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - _dateController.text = DateFormat("yyyy-MM-dd") - .format(DateFormat("yyyy-MM-dd").parse(selected.toString())); - }); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildTaskBlock(); - } else if (_currentTabIndex == 1) { - return buildDescriptionBlock(); - } - } - - Positioned buildReqField() { - return Positioned( - child: Container( - width: 3.0, - color: Colors.red, - ), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildTaskBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _taskFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Task Title ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - taskBloc.currentEditTask!['title'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - taskBloc.currentEditTask!['title'] = value; - }, - ), - ), - _errors['title'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['title'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Account ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => taskBloc.accountsObjforDropDown, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - taskBloc.currentEditTask!['account'] = ""; - } else { - taskBloc.currentEditTask!['account'] = - selection; - } - }, - selectedItem: - taskBloc.currentEditTask!['account'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a account", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['account'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['account'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Contacts", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - dataSource: contactBloc.contactsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Contacts", - ), - initialValue: - taskBloc.currentEditTask!['contacts'], - onSaved: (value) { - if (value == null) return; - taskBloc.currentEditTask!['contacts'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Status ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => taskBloc.status!, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - taskBloc.currentEditTask!['status'] = ""; - } else { - taskBloc.currentEditTask!['status'] = - selection; - } - }, - selectedItem: - taskBloc.currentEditTask!['status'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Status", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['status'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['status'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Priority ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - height: 48.0, - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownSearch( - items: (filter, infiniteScrollProps) => taskBloc.priorities!, - onChanged: print, - onSaved: (selection) { - if (selection == null) { - taskBloc.currentEditTask!['priority'] = ""; - } else { - taskBloc.currentEditTask!['priority'] = - selection; - } - }, - selectedItem: - taskBloc.currentEditTask!['priority'], - popupProps: PopupProps.bottomSheet( - itemBuilder: (context, item, isDisabled, isSelected) { - return Container( - padding: EdgeInsets.symmetric( - horizontal: 15.0, vertical: 10.0), - child: Text(item!, - style: TextStyle( - fontSize: screenWidth / 22)), - ); - }, - constraints: BoxConstraints(maxHeight: 400), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - border: boxBorder(), - enabledBorder: boxBorder(), - focusedErrorBorder: boxBorder(), - focusedBorder: boxBorder(), - errorBorder: boxBorder(), - contentPadding: EdgeInsets.all(12), - hintText: "Search a Priority", - )), - showSearchBox: true, - showSelectedItems: false, - ), - ), - ), - _errors['priority'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['priority'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Due Date ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: _dateController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: () { - _selectDate(context); - }, - icon: Icon(Icons.calendar_today_outlined), - ), - ), - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - taskBloc.currentEditTask!['due_date'] = value; - }, - ), - ), - _errors['due_date'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['due_date'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Assigned to", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Assigned to", - ), - initialValue: taskBloc - .currentEditTask!['assigned_to'], - onSaved: (value) { - if (value == null) return; - taskBloc.currentEditTask!['assigned_to'] = - value; - })) - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Teams", - style: TextStyle( - fontSize: 18, color: Colors.black54), - ), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: teamBloc.teamsObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "teams", - ), - initialValue: - taskBloc.currentEditTask!['teams'], - onSaved: (value) { - if (value == null) return; - taskBloc.currentEditTask!['teams'] = - value; - })) - ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: SizedBox() - // Column( - // children: [ - // quill.QuillToolbar.basic( - // controller: _controller, - // showAlignmentButtons: true, - // showBackgroundColorButton: false, - // showCameraButton: false, - // showImageButton: false, - // showVideoButton: false, - // showDividers: false, - // showColorButton: false, - // showUndo: false, - // showRedo: false, - // showQuote: false, - // showClearFormat: false, - // showIndent: false, - // showLink: false, - // showCodeBlock: false, - // showInlineCode: false, - // showListCheck: false, - // ), - // Expanded( - // child: Container( - // child: quill.QuillEditor.basic( - // controller: _controller, - // readOnly: true, - // ), - // ), - // ) - // ], - // ) - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - taskBloc.cancelCurrentEditTask(); - taskBloc.currentEditTaskId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - taskBloc.currentEditTaskId == "" - ? 'Add Task' - : "Edit Task", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_taskFormKey.currentState != null) - _taskFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Task', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_taskFormKey.currentState != null) { - if (!_taskFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _taskFormKey.currentState!.save(); - // setState(() { - // _currentTabIndex = 1; - // }); - await Future.delayed(const Duration(seconds: 1), () async {}); - - Map _result = {}; - if (taskBloc.currentEditTaskId != null && - taskBloc.currentEditTaskId != "") { - _result = await taskBloc.editTask(); - } else { - _result = await taskBloc.createTask(); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - taskBloc.cancelCurrentEditTask(); - taskBloc.currentEditTaskId = ""; - showToaster(_result['message'], context); - taskBloc.tasks.clear(); - await taskBloc.fetchTasks(); - await FirebaseAnalytics.instance.logEvent(name: "task_Created"); - Navigator.pushReplacementNamed(context, '/tasks_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _taskFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/tasks/task_details.dart b/lib/ui/screens/tasks/task_details.dart deleted file mode 100644 index f2d9a35..0000000 --- a/lib/ui/screens/tasks/task_details.dart +++ /dev/null @@ -1,583 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/task_bloc.dart'; -import 'package:bottle_crm/model/task.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; - -class TasskDeails extends StatefulWidget { - TasskDeails(); - @override - State createState() => _TasskDeailsState(); -} - -class _TasskDeailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Task Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - taskBloc.currentEditTaskId = - taskBloc.currentTask!.id.toString(); - await taskBloc - .updateCurrentEditTask(taskBloc.currentTask!); - Navigator.pushNamed(context, '/task_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Task Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - child: buildTaskInfoBlock(), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildTaskInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - taskBloc.currentTask!.title!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - padding: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: ColorBrightness.light), - child: Text( - taskBloc.currentTask!.status!, - style: TextStyle(color: Colors.white, fontSize: 12.0), - ), - ), - SizedBox(height: 5.0), - Container( - child: Container( - child: Row( - children: [ - Container( - child: ProfilePicViewWidget(taskBloc - .currentTask!.assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser.firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - ], - ), - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Create Date :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - taskBloc.currentTask!.createdOn!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Closed on :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - taskBloc.currentTask!.dueDate! == "" - ? "-----" - : taskBloc.currentTask!.dueDate!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Status :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - taskBloc.currentTask!.status!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - ], - )), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - taskBloc.currentTask!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${taskBloc.currentTask!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: - Icon(Icons.email_outlined, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "account@mp.com", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "------------", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Priority :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - taskBloc.currentTask!.priority == "" - ? "------" - : taskBloc.currentTask!.priority!, - style: TextStyle( - color: taskBloc.currentTask!.priority == "" - ? Colors.black45 - : Colors.blue, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteTaskAlertDialog(context, taskBloc.currentTask!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))); - } - - void showDeleteTaskAlertDialog(BuildContext context, Task task) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - task.title != "" ? task.title!.capitalizeFirstofEach() : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this Task?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteTask(task); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteTask(Task task) async { - setState(() { - _isLoading = true; - }); - Map result = await taskBloc.deleteTask(task); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - taskBloc.tasks.clear(); - await taskBloc.fetchTasks(); - await FirebaseAnalytics.instance.logEvent(name: "Task_Deleted"); - Navigator.pushReplacementNamed(context, '/tasks_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, result['message'].toString(), task); - } - } - - showErrorMessage(BuildContext context, msg, Task task) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteTask(task); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/tasks/tasks_list.dart b/lib/ui/screens/tasks/tasks_list.dart deleted file mode 100644 index 3024699..0000000 --- a/lib/ui/screens/tasks/tasks_list.dart +++ /dev/null @@ -1,570 +0,0 @@ -import 'package:bottle_crm/model/task.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -//import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:bottle_crm/bloc/task_bloc.dart'; - -class TasksList extends StatefulWidget { - TasksList(); - @override - State createState() => _TasksListState(); -} - -class _TasksListState extends State { - final GlobalKey _filtersFormKey = GlobalKey(); - List _tasks = []; - bool _isFilter = false; - ScrollController? scrollController; - bool _isNextPageLoading = false; - Map _filtersFormData = {"title": "", "status": "", "priority": ""}; - bool _isLoading = false; - - @override - void initState() { - setState(() { - _tasks = taskBloc.tasks; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - taskBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await taskBloc.fetchTasks( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - taskBloc.offset = ""; - taskBloc.tasks.clear(); - await taskBloc.fetchTasks(filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['title'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter title", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['title'] = value; - }, - ), - ), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Status", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: taskBloc.status, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // taskBloc.currentEditTask!["status"] = - // ""; - // } else { - // taskBloc.currentEditTask!['status '] = - // selection; - // } - // }, - // selectedItem: - // taskBloc.currentEditTask!['status '], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Status", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Status', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Priority", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: taskBloc.priorities, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // taskBloc.currentEditTask!["priority"] = - // ""; - // } else { - // taskBloc.currentEditTask!["priority"] = - // selection; - // } - // }, - // selectedItem: - // taskBloc.currentEditTask!['priority '], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Source", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Priority', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - SizedBox(height: 10.0), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "title": "", - "status": [], - "priority": [] - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - Widget _buildTasksList() { - return _tasks.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _tasks.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - taskBloc.currentTask = _tasks[index]; - Navigator.pushNamed(context, '/task_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _tasks[index] - .title! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Text(_tasks[index].createdOn!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - children: [ - Container( - child: ProfilePicViewWidget( - _tasks[index] - .assignedTo! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser - .firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - ], - ), - ), - Container( - padding: EdgeInsets.symmetric( - horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor( - colorBrightness: ColorBrightness.light), - child: Text( - _tasks[index].status!, - style: TextStyle( - color: Colors.white, fontSize: 12.0), - ), - ), - ], - ), - ) - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Accounts Found.'), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - Navigator.pushReplacementNamed( - context, "/dashboard"); - currentBottomNavigationIndex="0"; - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Tasks', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, - child: _buildTasksList(), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - taskBloc.currentEditTaskId = ""; - if (taskBloc.tasks.length == 0) { - showAlertDialog(context); - } else { - Navigator.pushNamed(context, '/task_create'); - } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any accounts, Please create account first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/task_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/teams/team_create.dart b/lib/ui/screens/teams/team_create.dart deleted file mode 100644 index 697daea..0000000 --- a/lib/ui/screens/teams/team_create.dart +++ /dev/null @@ -1,516 +0,0 @@ -import 'dart:io'; - -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:multiselect_formfield/multiselect_formfield.dart'; -import 'package:flutter_quill/flutter_quill.dart' as quill; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class CreateTeam extends StatefulWidget { - CreateTeam(); - @override - State createState() => _CreateTeamState(); -} - -class _CreateTeamState extends State { - quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _teamFormKey = GlobalKey(); - var _currentTabIndex = 0; - Map _errors = {}; - bool _isLoading = false; - File? file = File(''); - List _teamFormKeys = [ - 'name', - 'assign_users', - ]; - - List _deskey = [ - 'description', - ]; - - @override - void initState() { - super.initState(); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - if (_teamFormKey.currentState != null) { - _teamFormKey.currentState!.save(); - } - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildTeamBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildDescriptionBlock()); - } - } - - Positioned buildReqField() { - return Positioned( - child: Container( - width: 3.0, - color: Colors.red, - ), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - Widget buildTeamBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _teamFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Team Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: teamBloc.currentEditTeam!['name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - teamBloc.currentEditTeam!['name'] = value; - }, - ), - ), - _errors['name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Assign Users ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - child: MultiSelectFormField( - border: boxBorder(), - fillColor: Colors.white, - validator: (value) { - if (value == null) { - return 'Please select one or more options'; - } - return null; - }, - dataSource: userBloc.usersObjForDropdown, - textField: 'name', - valueField: 'id', - okButtonLabel: 'OK', - chipLabelStyle: - TextStyle(color: Colors.black), - cancelButtonLabel: 'CANCEL', - // required: true, - hintWidget: Text( - "Please choose one or more", - style: TextStyle(color: Colors.grey), - ), - title: Text( - "Assigned to", - ), - initialValue: teamBloc - .currentEditTeam!['assign_users'], - onSaved: (value) { - if (value == null) return; - teamBloc.currentEditTeam![ - 'assign_users'] = value; - })) - ])), - ]))))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - quill.QuillSimpleToolbar( - controller: _controller, - config: const quill.QuillSimpleToolbarConfig(), - ), - Expanded( - child: Container( - child: quill.QuillEditor.basic( - controller: _controller, - config: const quill.QuillEditorConfig()), - ), - ) - ], - )); - } - - @override - Widget build(BuildContext context) { - // Set readOnly property based on loading state - _controller.readOnly = _isLoading; - - return Scaffold( - resizeToAvoidBottomInset: false, - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - teamBloc.cancelCurrentEditTeam(); - teamBloc.currentEditTeamId = ""; - FocusScope.of(context).unfocus(); - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - teamBloc.currentEditTeamId == "" - ? 'Add Team' - : "Edit Team", - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - if (_teamFormKey.currentState != null) - _teamFormKey.currentState!.save(); - FocusScope.of(context).unfocus(); - // teamBloc.currentEditTeam!['description'] = - // _controller.document.toPlainText(); - if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Team', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_teamFormKey.currentState != null) - _teamFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_teamFormKey.currentState != null) { - if (!_teamFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _teamFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - await Future.delayed(const Duration(seconds: 1), () async {}); - // if (_controller.getPlainText().isEmpty) { - // setState(() { - // _isLoading = false; - // }); - // showToaster('⚠ Please enter Description.', context); - // return; - // } - - Map _result = {}; - if (teamBloc.currentEditTeamId != null && - teamBloc.currentEditTeamId != "") { - _result = await teamBloc.editTeam(); - } else { - _result = await teamBloc.createTeam(); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - teamBloc.cancelCurrentEditTeam(); - teamBloc.currentEditTeamId = ""; - showToaster(_result['message'], context); - teamBloc.teams.clear(); - await teamBloc.fetchTeams(); - await FirebaseAnalytics.instance.logEvent(name: "team_Created"); - Navigator.pushReplacementNamed(context, '/teams_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _teamFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - for (var key in _deskey) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 1; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/teams/team_details.dart b/lib/ui/screens/teams/team_details.dart deleted file mode 100644 index 1d00257..0000000 --- a/lib/ui/screens/teams/team_details.dart +++ /dev/null @@ -1,523 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/model/team.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; - -class TeamkDeails extends StatefulWidget { - TeamkDeails(); - @override - State createState() => _TeamDeailsState(); -} - -class _TeamDeailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Team Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - teamBloc.currentEditTeamId = - teamBloc.currentTeam!.id.toString(); - await teamBloc - .updateCurrentEditTeam(teamBloc.currentTeam!); - Navigator.pushNamed(context, '/team_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'Team Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - child: buildteamInfoBlock(), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildteamInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Text( - teamBloc.currentTeam!.name!.capitalizeFirstofEach(), - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ), - SizedBox(height: 5.0), - Container( - child: Container( - child: Row( - children: [ - Container( - child: ProfilePicViewWidget(teamBloc - .currentTeam!.users! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser.firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - ], - ), - ), - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Create Date :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - teamBloc.currentTeam!.createdOn!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.29, - child: Text( - "Closed on :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Status :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - ], - )), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Text( - teamBloc.currentTeam!.createdBy!.firstName! - .capitalizeFirstofEach() + - " ${teamBloc.currentTeam!.createdBy!.lastName!}", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: - Icon(Icons.email_outlined, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "account@mp.com", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "------------", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - GestureDetector( - onTap: () { - if (!_isLoading) - showDeleteteamAlertDialog(context, teamBloc.currentTeam!); - }, - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.red.shade100), - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.25, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/icon_delete_color.svg', - width: screenWidth / 25, - ), - SizedBox(width: 10.0), - Container( - child: Text( - "Delete", - style: TextStyle( - fontSize: screenWidth / 23, - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ]))); - } - - void showDeleteteamAlertDialog(BuildContext context, Team team) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - team.name != "" ? team.name!.capitalizeFirstofEach() : "", - style: TextStyle(color: Colors.black), - ), - content: Text( - "Are you sure you want to delete this team?", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - deleteTeam(team); - }, - child: Text("Delete")), - ], - ); - }); - } - - deleteTeam(Team team) async { - setState(() { - _isLoading = true; - }); - Map result = await teamBloc.deleteTeam(team); - setState(() { - _isLoading = false; - }); - if (result['error'] == false) { - showToaster(result['message'], context); - teamBloc.teams.clear(); - await teamBloc.fetchTeams(); - await FirebaseAnalytics.instance.logEvent(name: "team_Deleted"); - Navigator.pushReplacementNamed(context, '/teams_list'); - } else if (result['error'] == true) { - showToaster(result['message'], context); - } else { - showErrorMessage(context, result['message'].toString(), team); - } - } - - showErrorMessage(BuildContext context, msg, Team team) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - deleteTeam(team); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/teams/teams_list.dart b/lib/ui/screens/teams/teams_list.dart deleted file mode 100644 index 3111837..0000000 --- a/lib/ui/screens/teams/teams_list.dart +++ /dev/null @@ -1,562 +0,0 @@ -import 'package:bottle_crm/model/team.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:bottle_crm/ui/widgets/profile_pic_widget.dart'; -//import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; - -class TeamsList extends StatefulWidget { - TeamsList(); - @override - State createState() => _TeamsListState(); -} - -class _TeamsListState extends State { - final GlobalKey _filtersFormKey = GlobalKey(); - List _teams = []; - bool _isFilter = false; - ScrollController? scrollController; - bool _isNextPageLoading = false; - Map _filtersFormData = { - "team_name": "", - "created_by": "", - "assigned_users": "" - }; - bool _isLoading = false; - - @override - void initState() { - setState(() { - _teams = teamBloc.teams; - }); - scrollController = ScrollController(); - scrollController!.addListener(() async { - if (scrollController!.offset >= - scrollController!.position.maxScrollExtent && - !scrollController!.position.outOfRange && - teamBloc.offset != "" && - !_isNextPageLoading) { - setState(() { - _isNextPageLoading = true; - }); - await teamBloc.fetchTeams( - filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isNextPageLoading = false; - }); - } - }); - super.initState(); - } - - _submitForm() async { - if (_isFilter) { - _filtersFormKey.currentState!.save(); - } - setState(() { - _isLoading = true; - }); - teamBloc.offset = ""; - teamBloc.teams.clear(); - await teamBloc.fetchTeams(filtersData: _isFilter ? _filtersFormData : null); - setState(() { - _isLoading = false; - }); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _buildFilterBlock() { - return _isFilter - ? Container( - color: Colors.grey[100], - child: Form( - key: _filtersFormKey, - child: Column( - children: [ - SizedBox(height: 10.0), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: _filtersFormData['team_name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - fillColor: Colors.white, - filled: true, - hintText: "Enter team name", - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - onSaved: (value) { - _filtersFormData['team name'] = value; - }, - ), - ), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Created by", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: teamBloc.userObjForDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // teamBloc.currentEditTeam![ - // "created_by"] = ""; - // } else { - // teamBloc.currentEditTeam![ - // 'created_by'] = selection; - // } - // }, - // selectedItem: - // teamBloc.currentEditTeam!['created_by'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a user", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'Created By', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // "Users", - // style: TextStyle( - // fontSize: 18, color: Colors.black54), - // ), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // height: screenHeight / 17, - // child: Stack(children: [ - // DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: teamBloc.userObjForDropDown, - // onChanged: print, - // onSaved: (selection) { - // if (selection == null) { - // teamBloc.currentEditTeam![ - // "assigned_users"] = ""; - // } else { - // teamBloc.currentEditTeam![ - // "assigned_users"] = selection; - // } - // }, - // selectedItem: teamBloc - // .currentEditTeam!['assigned_users '], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Source", - // )), - // popupTitle: Container( - // height: 50, - // decoration: BoxDecoration( - // color: - // Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'assigned users', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: - // (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // ), - // ])), - // ])), - SizedBox(height: 10.0), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Theme.of(context).primaryColor, - ), - onPressed: () { - setState(() { - _isFilter = false; - }); - FocusScope.of(context).unfocus(); - setState(() { - _filtersFormData = { - "team_name": "", - "created_by": [], - "assigned_users": [] - }; - }); - _submitForm(); - }, - child: Text( - "Reset", - style: TextStyle(fontSize: screenWidth / 24), - )), - SizedBox(width: 20.0), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Theme.of(context).primaryColor, - foregroundColor: Colors.white, - ), - onPressed: () { - FocusScope.of(context).unfocus(); - _submitForm(); - }, - child: Text( - "Filter", - style: TextStyle(fontSize: screenWidth / 24), - )), - ], - ) - ], - ), - )) - : Container(); - } - - Widget _buildTeamsList() { - return _teams.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _teams.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - teamBloc.currentTeam = _teams[index]; - Navigator.pushNamed(context, '/team_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _teams[index] - .name! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Text(_teams[index].createdOn!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)) - ], - ), - ), - SizedBox(height: 5.0), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - children: [ - Container( - child: ProfilePicViewWidget(_teams[ - index] - .users! - .map((assignedUser) => - assignedUser.profileUrl == "" - ? assignedUser - .firstName![0].inCaps - : assignedUser.profileUrl) - .toList()), - ), - ], - ), - ), - ], - ), - ) - ], - ), - )); - }), - ) - : Center( - child: Text(_isLoading || _isNextPageLoading - ? "Fetching data..." - : 'No Teams Found.'), - ); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () { - Navigator.pushReplacementNamed( - context, "/more_options"); - }, - child: Icon(Icons.arrow_back_ios, - color: Colors.white, - size: screenWidth / 18)), - SizedBox(width: 10.0), - Text( - 'Teams', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - Container( - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - ), - ], - ), - ), - _buildFilterBlock(), - Expanded( - child: Container( - color: Colors.white, - child: _buildTeamsList(), - ), - ), - _isNextPageLoading - ? Container( - color: Colors.white, - child: Container( - width: 20.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())))) - : Container() - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ]), - floatingActionButton: FloatingActionButton( - onPressed: () { - teamBloc.currentEditTeamId = ""; - if (teamBloc.teams.length == 0) { - showAlertDialog(context); - } else { - Navigator.pushNamed(context, '/team_create'); - } - }, - child: Icon(Icons.add, color: Colors.white), - backgroundColor: Theme.of(context).primaryColor, - ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any team, Please create team first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/team_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/screens/users/user_create.dart b/lib/ui/screens/users/user_create.dart deleted file mode 100644 index 24cff09..0000000 --- a/lib/ui/screens/users/user_create.dart +++ /dev/null @@ -1,1222 +0,0 @@ -import 'dart:io'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -//import 'package:dropdown_search/dropdown_search.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter/services.dart'; -//import 'package:flutter_quill/flutter_quill.dart' as quill; -import 'package:file_picker/file_picker.dart'; - -class CreateUser extends StatefulWidget { - CreateUser(); - @override - State createState() => _CreateUserState(); -} - -class _CreateUserState extends State { - int _currentTabIndex = 0; - //quill.QuillController _controller = quill.QuillController.basic(); - final GlobalKey _userFormKey = GlobalKey(); - final GlobalKey _addressFormKey = GlobalKey(); - TextEditingController fileNameController = new TextEditingController(); - File file = new File(''); - List _userFormKeys = [ - 'username', - 'role', - 'profile_pic', - 'date_joined', - 'email', - "password", - 'first_name', - 'last_name', - 'has_marketing_access', - 'has_sales_access', - 'is_active', - 'is_admin', - ]; - List _addressFormKeys = [ - "address_line ", - "street", - "city", - "state", - "pincode", - "country" - ]; - Map _errors = {}; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - OutlineInputBorder boxBorder() { - return OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(width: 1, color: Colors.black45), - ); - } - - OutlineInputBorder buildBorder(Color color) { - return OutlineInputBorder( - borderSide: BorderSide(color: color, width: 1.0), - borderRadius: BorderRadius.all(Radius.circular(3.0))); - } - - EdgeInsets padding() { - return EdgeInsets.symmetric( - horizontal: screenWidth / 30, vertical: screenHeight / 80); - } - - _filePicker() async { - FilePickerResult? result = - await FilePicker.platform.pickFiles(allowMultiple: false); - if (result != null) { - file = File(result.files[0].path!); - var _filename = file.path.toString(); - var split = _filename.split('/'); - Map values = { - for (int i = 0; i < split.length; i++) i: split[i] - }; - setState(() { - fileNameController.text = values[7].toString(); - }); - } else {} - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return buildUserBlock(); - } else if (_currentTabIndex == 1) { - return buildAddressBlock(); - } else if (_currentTabIndex == 2) { - return buildDescriptionBlock(); - } - } - - Widget buildUserBlock() { - return Container( - child: SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _userFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'First Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - userBloc.currentEditUser['first_name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['first_name'] = - value; - }, - ), - ), - _errors['first_name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['first_name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - verticalDirection: VerticalDirection.down, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Lase Name ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - userBloc.currentEditUser['last_name'], - cursorWidth: 3.0, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['last_name'] = value; - }, - ), - ), - _errors['last_name'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['last_name'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Phone ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['phone'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - hintText: '+91XXXXXXXXXX', - ), - keyboardType: TextInputType.phone, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['phone'] = value; - }, - ), - ), - _errors['phone'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['phone'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Primary Email ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['email'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - if (value.isNotEmpty && - !RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(value)) { - return 'Enter valid email address.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['email'] = value; - }, - ), - ), - _errors['email'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['email'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Secondary Email ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['email'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - if (value.isNotEmpty && - !RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+") - .hasMatch(value)) { - return 'Enter valid email address.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['alternate_email'] = - value; - }, - ), - ), - _errors['alternate_email'] != null - ? Container( - margin: EdgeInsets.only(top: 5.0), - alignment: Alignment.centerLeft, - child: Text( - _errors['alternate_email'][0], - style: TextStyle( - color: Colors.red[700], - fontSize: 12.0), - ), - ) - : Container(), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Role", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownButtonFormField( - decoration: InputDecoration( - border: boxBorder(), - contentPadding: EdgeInsets.all(12.0)), - style: TextStyle(color: Colors.black), - hint: Text('select Role'), - value: userBloc.currentEditUser['role'], - onChanged: (value) { - userBloc.currentEditUser['role'] = value; - }, - items: userBloc.rolesObjForDropdown.map((item) { - return DropdownMenuItem( - child: new Text(item), - value: item, - ); - }).toList(), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Status", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - margin: EdgeInsets.only(bottom: 5.0), - child: DropdownButtonFormField( - decoration: InputDecoration( - border: boxBorder(), - contentPadding: EdgeInsets.all(12.0)), - style: TextStyle(color: Colors.black), - hint: Text('select Status'), - value: userBloc.currentEditUser['status'], - onChanged: (value) { - userBloc.currentEditUser['status'] = value; - }, - items: - userBloc.statusObjForDropdown.map((item) { - return DropdownMenuItem( - child: new Text(item), - value: item, - ); - }).toList(), - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Attachment", - style: buildLableTextStyle(), - ), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - controller: fileNameController, - readOnly: true, - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 5.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: - buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - suffixIcon: IconButton( - onPressed: _filePicker, - icon: Icon(Icons.upload))), - ), - ), - ])), - ]))))); - } - - Widget buildAddressBlock() { - return SingleChildScrollView( - scrollDirection: Axis.vertical, - child: Form( - key: _addressFormKey, - child: Container( - child: Column(children: [ - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Billing Address Line ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: - userBloc.currentEditUser['address_line '], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['address_line '] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Billing Street ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['street'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['street'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'City ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['city'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['city'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'State ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['state'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['state'] = value; - }, - ), - ), - ])), - Container( - padding: padding(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerLeft, - margin: EdgeInsets.only(bottom: 5.0), - child: RichText( - text: TextSpan( - text: 'Pincode ', - style: buildLableTextStyle(), - children: [ - TextSpan( - text: '* ', - style: TextStyle( - color: Colors.red, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500)) - ], - ), - )), - SizedBox(height: screenHeight / 70), - Container( - width: screenWidth * 0.92, - child: TextFormField( - initialValue: userBloc.currentEditUser['pincode'], - decoration: new InputDecoration( - contentPadding: new EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - enabledBorder: buildBorder(Colors.black54), - focusedErrorBorder: buildBorder(Colors.black54), - focusedBorder: buildBorder(Colors.black54), - errorBorder: buildBorder(Colors.black54), - border: buildBorder(Colors.black54), - ), - keyboardType: TextInputType.text, - validator: (value) { - if (value!.isEmpty) { - return 'This field is required.'; - } - return null; - }, - onSaved: (value) { - userBloc.currentEditUser['pincode'] = value; - }, - ), - ), - ])), - // Container( - // padding: padding(), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // alignment: Alignment.centerLeft, - // margin: EdgeInsets.only(bottom: 5.0), - // child: RichText( - // text: TextSpan( - // text: 'Country ', - // style: buildLableTextStyle(), - // children: [ - // TextSpan( - // text: '* ', - // style: TextStyle( - // color: Colors.red, - // fontSize: screenWidth / 25, - // fontWeight: FontWeight.w500)) - // ], - // ), - // )), - // SizedBox(height: screenHeight / 70), - // Container( - // width: screenWidth * 0.92, - // child: DropdownSearch( - // mode: Mode.BOTTOM_SHEET, - // items: leadBloc.countries, - // onChanged: print, - // selectedItem: userBloc.currentEditUser['country'], - // showSearchBox: true, - // showSelectedItems: false, - // showClearButton: false, - // searchFieldProps: TextFieldProps( - // decoration: InputDecoration( - // border: boxBorder(), - // enabledBorder: boxBorder(), - // focusedErrorBorder: boxBorder(), - // focusedBorder: boxBorder(), - // errorBorder: boxBorder(), - // contentPadding: EdgeInsets.all(12), - // hintText: "Search a Country", - // )), - // popupTitle: Container( - // decoration: BoxDecoration( - // color: Theme.of(context).primaryColorDark, - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(20), - // topRight: Radius.circular(20), - // ), - // ), - // child: Center( - // child: Text( - // 'County', - // style: TextStyle( - // fontSize: screenWidth / 20, - // color: Colors.white), - // ), - // ), - // ), - // popupItemBuilder: (context, item, isSelected) { - // return Container( - // padding: EdgeInsets.symmetric( - // horizontal: 15.0, vertical: 10.0), - // child: Text(item!, - // style: TextStyle( - // fontSize: screenWidth / 22)), - // ); - // }, - // popupShape: RoundedRectangleBorder( - // borderRadius: BorderRadius.only( - // topLeft: Radius.circular(24), - // topRight: Radius.circular(24), - // ), - // ), - // validator: (value) { - // if (value == null || value.isEmpty) { - // return 'This field is required.'; - // } - // return null; - // }, - // onSaved: (newValue) { - // userBloc.currentEditUser['country'] = newValue; - // }, - // )), - // ])) - ])))); - } - - Widget buildDescriptionBlock() { - return Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(5.0), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey, - width: 1.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: SizedBox() - // Column( - // children: [ - // quill.QuillToolbar.basic( - // controller: _controller, - // showAlignmentButtons: true, - // showBackgroundColorButton: false, - // showCameraButton: false, - // showImageButton: false, - // showVideoButton: false, - // showDividers: false, - // showColorButton: false, - // showUndo: false, - // showRedo: false, - // showQuote: false, - // showClearFormat: false, - // showIndent: false, - // showLink: false, - // showCodeBlock: false, - // showInlineCode: false, - // showListCheck: false, - // ), - // Expanded( - // child: Container( - // child: quill.QuillEditor.basic( - // controller: _controller, - // readOnly: true, - // ), - // ), - // ) - // ], - // ) - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Container( - decoration: BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - size: screenWidth / 18, color: Colors.white), - onTap: () { - // userBloc.cancelCurrentEditUser(); - // userBloc.currentEditUserId = ""; - // FocusScope.of(context).unfocus(); - // Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Add User', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () { - // if (_userFormKey.currentState != null) - // _userFormKey.currentState!.save(); - // if (_addressFormKey.currentState != null) - // _addressFormKey.currentState!.save(); - // FocusScope.of(context).unfocus(); - // if (!_isLoading) _submitForm(); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Icon(Icons.check, - color: Theme.of(context).primaryColor, - size: screenWidth / 18), - Container( - child: Text( - "Save", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'User', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_userFormKey.currentState != null) - _userFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.20, - child: Text( - 'Address', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - if (_userFormKey.currentState != null) - _userFormKey.currentState!.save(); - if (_addressFormKey.currentState != null) - _addressFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.25, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context).secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - Expanded( - child: Stack( - fit: StackFit.expand, - children: [ - Container( - color: Colors.white, - child: buildTopBar(), - ), - new Align( - child: _isLoading - ? Container( - color: Colors.white, - width: screenWidth, - height: screenHeight * 0.9, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center( - child: new CircularProgressIndicator())), - ) - : Container(), - alignment: FractionalOffset.center, - ) - ], - )) - ], - ), - ), - ), - ); - } - - _submitForm() async { - setState(() { - _errors = {}; - _isLoading = true; - }); - _currentTabIndex = 0; - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_userFormKey.currentState != null) { - if (!_userFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _userFormKey.currentState!.save(); - setState(() { - _currentTabIndex = 1; - }); - await Future.delayed(const Duration(seconds: 1), () async {}); - if (_addressFormKey.currentState != null) { - if (!_addressFormKey.currentState!.validate()) { - setState(() { - _isLoading = false; - }); - showToaster('⚠ Please enter required fields.', context); - return; - } - _addressFormKey.currentState!.save(); - Map _result = {}; - if (userBloc.currentEditUserId != null && - userBloc.currentEditUserId != "") { - _result = await userBloc.editUser(); - } else { - _result = await userBloc.createUser(file: file); - } - setState(() { - _isLoading = false; - }); - if (_result['error'] == false) { - setState(() { - _errors = {}; - }); - userBloc.cancelCurrentEditUser()(); - userBloc.currentEditUserId = ""; - showToaster(_result['message'], context); - Navigator.pushReplacementNamed(context, '/users_list'); - } else if (_result['error'] == true) { - setState(() { - _errors = _result['errors']; - }); - for (var key in _userFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 0; - }); - showToaster(_errors[key][0], context); - return; - } - } - for (var key in _addressFormKeys) { - if (_errors.containsKey(key)) { - setState(() { - _currentTabIndex = 1; - }); - showToaster(_errors[key][0], context); - return; - } - } - } else { - setState(() { - _errors = {}; - }); - showErrorMessage(context, _result['message'].toString()); - } - } - } - } - - showErrorMessage(BuildContext context, msg) { - return showDialog( - context: context, - builder: (_) => AlertDialog( - title: Text('Alert'), - content: Text(msg), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - _submitForm(); - }, - child: Text('RETRY')) - ], - )); - } -} diff --git a/lib/ui/screens/users/user_details.dart b/lib/ui/screens/users/user_details.dart deleted file mode 100644 index 2f04a4f..0000000 --- a/lib/ui/screens/users/user_details.dart +++ /dev/null @@ -1,581 +0,0 @@ -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:bottle_crm/ui/widgets/loader.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class UserDetails extends StatefulWidget { - UserDetails(); - @override - State createState() => _UserDetailsState(); -} - -class _UserDetailsState extends State { - var _currentTabIndex = 0; - bool _isLoading = false; - - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - Widget loadingIndicator = _isLoading ? Loader() : new Container(); - return Scaffold( - body: Stack( - fit: StackFit.expand, - children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row(children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'User Details', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ]), - ), - GestureDetector( - onTap: () async { - if (!_isLoading) { - userBloc.currentEditUserId = - userBloc.currentUser!.id.toString(); - await userBloc - .updateCurrentEditUser(userBloc.currentUser!); - Navigator.pushNamed(context, '/user_create'); - } - }, - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(3.0)), - color: Colors.white, - ), - width: screenWidth * 0.18, - height: screenHeight * 0.04, - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SvgPicture.asset( - 'assets/images/Icon_edit_color.svg', - colorFilter: ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn), - width: screenWidth / 25, - ), - Container( - child: Text( - "Edit", - style: TextStyle( - fontSize: screenWidth / 25, - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 23.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 0; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.40, - child: Text( - 'User Information', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 1; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.22, - child: Text( - 'Attachment', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - setState(() { - _currentTabIndex = 2; - }); - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 2 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.21, - child: Text( - 'Description', - style: TextStyle( - color: _currentTabIndex == 2 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - child: buildTopBar(), - color: Colors.white, - )) - ], - ), - ), - ), - new Align( - child: loadingIndicator, - alignment: FractionalOffset.center, - ) - ], - ), - ); - } - - buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildUserInfoBlock()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 2; - }); - }, - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: buildAttachmentBlock()); - } else if (_currentTabIndex == 2) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 1; - }); - }, - child: buildDescriptionBlock()); - } - } - - buildAttachmentBlock() { - return Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text("No Attachments Found."), - ); - } - - buildDescriptionBlock() { - return Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text("No Notes Found."), - ); - } - - buildUserInfoBlock() { - return Container( - padding: EdgeInsets.all(10.0), - child: SingleChildScrollView( - child: Column(children: [ - Container( - width: screenWidth, - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "First Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.firstName! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Last Name :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.lastName == "" - ? "----" - : userBloc.currentUser!.lastName! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - SizedBox(height: 10.0), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Role :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.role!, - //.capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - ], - )), - ], - ), - ], - ), - ), - SizedBox(height: 10.0), - Container( - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Organization :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - authBloc.selectedOrganization!.name! - .capitalizeFirstofEach(), - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - SizedBox(height: 5.0), - Text( - "https//:www.micropyramid.com", - style: TextStyle( - color: Colors.blue, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 25), - ), - ], - )), - ], - ), - SizedBox(height: 10), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Contact :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10.0), - ], - ), - SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: - Icon(Icons.email_outlined, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.email!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Icon(Icons.phone, size: screenWidth / 20)), - SizedBox(width: 10.0), - Container( - width: screenWidth * 0.50, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - userBloc.currentUser!.phone!, - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 5.0), - child: Divider()) - ], - )), - ], - ), - Row( - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Image.asset( - "assets/images/skype.png", - width: screenWidth / 22, - )), - // SizedBox(width: 10.0), - // Container( - // width: screenWidth * 0.50, - // child: Text( - // " skype@Id", - // style: TextStyle( - // color: Colors.blue, - // fontWeight: FontWeight.w600, - // fontSize: screenWidth / 24), - // )), - ], - ), - ], - ), - ), - SizedBox(height: 10), - Container( - padding: EdgeInsets.all(20.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.black12), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column(children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - alignment: Alignment.centerRight, - width: screenWidth * 0.28, - child: Text( - "Address :", - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - SizedBox(width: 10), - Container( - width: screenWidth * 0.50, - child: Text( - "${userBloc.currentUser!.adressLine} ${userBloc.currentUser!.street!}, ${userBloc.currentUser!.city!}, ${userBloc.currentUser!.state!}, ${userBloc.currentUser!.country!}, ${userBloc.currentUser!.pincode!}.", - style: TextStyle( - color: Colors.black45, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24), - )), - ], - ), - ])), - SizedBox(height: 10.0), - ]))); - } -} diff --git a/lib/ui/screens/users/users_list.dart b/lib/ui/screens/users/users_list.dart deleted file mode 100644 index ef8aba8..0000000 --- a/lib/ui/screens/users/users_list.dart +++ /dev/null @@ -1,427 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:bottle_crm/model/user.dart'; -import 'package:bottle_crm/ui/widgets/bottom_navigation_bar.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; - -class UsersList extends StatefulWidget { - UsersList(); - @override - State createState() => _UsersListState(); -} - -class _UsersListState extends State { - var _currentTabIndex = 0; - ScrollController? scrollController; - - bool _isFilter = false; - - List _activeUsers = []; - List _inActiveUsers = []; - @override - void initState() { - _activeUsers = userBloc.activeUsers; - _inActiveUsers = userBloc.inActiveUsers; - super.initState(); - } - - _buildTopBar() { - if (_currentTabIndex == 0) { - return SwipeDetector( - onSwipeLeft: (offset) { - setState(() { - _currentTabIndex = 1; - _inActiveUsers = userBloc.inActiveUsers; - }); - }, - child: _buildActiveUsersList()); - } else if (_currentTabIndex == 1) { - return SwipeDetector( - onSwipeRight: (offset) { - setState(() { - _currentTabIndex = 0; - }); - }, - child: _buildInActiveUsersList()); - } - } - - Widget _buildActiveUsersList() { - return _activeUsers.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _activeUsers.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - userBloc.currentUser = _activeUsers[index]; - Navigator.pushNamed(context, '/user_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - children: [ - _activeUsers[index].profilePic != "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _activeUsers[index].profilePic!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context).primaryColor, - child: Text( - _activeUsers[index] - .firstName![0] - .allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ), - SizedBox(width: 10.0), - Column( - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _activeUsers[index] - .firstName! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Container( - width: screenWidth * 0.55, - child: Text(_activeUsers[index].role!, - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.grey, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 30)), - ), - ], - ), - ], - ), - ), - SizedBox(height: 5.0), - ], - ), - )); - }), - ) - : Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text('No Users Found.'), - ); - } - - Widget _buildInActiveUsersList() { - return _inActiveUsers.length != 0 - ? Container( - padding: EdgeInsets.all(10.0), - child: ListView.builder( - itemCount: _inActiveUsers.length, - physics: const AlwaysScrollableScrollPhysics(), - shrinkWrap: true, - controller: scrollController, - itemBuilder: (BuildContext context, int index) { - return GestureDetector( - onTap: () { - userBloc.currentUser = _inActiveUsers[index]; - Navigator.pushNamed(context, '/user_details'); - }, - child: Container( - margin: EdgeInsets.only(bottom: 8.0), - padding: EdgeInsets.all(10.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - children: [ - _inActiveUsers[index].profilePic != "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage( - _inActiveUsers[index] - .profilePic!), - ) - : CircleAvatar( - radius: screenWidth / 25, - backgroundColor: - Theme.of(context).primaryColor, - child: Text( - _inActiveUsers[index] - .firstName![0] - .allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ), - SizedBox(width: 10.0), - Column( - children: [ - Container( - width: screenWidth * 0.55, - child: Text( - _inActiveUsers[index] - .firstName! - .capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w600, - fontSize: screenWidth / 24)), - ), - Container( - width: screenWidth * 0.55, - child: Text(_inActiveUsers[index].role!, - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.grey, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 30)), - ), - ], - ), - ], - ), - ), - SizedBox(height: 5.0), - ], - ), - )); - }), - ) - : Container( - alignment: Alignment.center, - color: Colors.white, - height: screenHeight, - width: screenWidth, - child: Text('No Users Found.')); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - resizeToAvoidBottomInset: false, - body: Stack(fit: StackFit.expand, children: [ - SafeArea( - child: Container( - decoration: - BoxDecoration(color: Color.fromRGBO(73, 128, 255, 1.0)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - child: Row( - children: [ - GestureDetector( - child: new Icon(Icons.arrow_back_ios, - color: Colors.white), - onTap: () { - Navigator.pop(context, true); - }), - SizedBox(width: 10.0), - Text( - 'Users', - style: TextStyle( - color: Colors.white, - fontSize: screenWidth / 20, - fontWeight: FontWeight.bold), - ), - ], - ), - ), - GestureDetector( - onTap: () { - setState(() { - _isFilter = !_isFilter; - }); - }, - child: Container( - child: SvgPicture.asset( - !_isFilter - ? 'assets/images/filter.svg' - : 'assets/images/icon_close.svg', - width: screenWidth / 20, - ))) - ], - ), - ), - Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25.0), - height: screenHeight * 0.06, - decoration: BoxDecoration( - color: bottomNavBarSelectedTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - if (_currentTabIndex != 0) { - setState(() { - _currentTabIndex = 0; - _activeUsers = userBloc.activeUsers; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 0 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Open', - style: TextStyle( - color: _currentTabIndex == 0 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ), - GestureDetector( - onTap: () { - FocusScope.of(context).unfocus(); - if (_currentTabIndex != 1) { - setState(() { - _currentTabIndex = 1; - _inActiveUsers = userBloc.inActiveUsers; - }); - } - }, - child: Container( - alignment: Alignment.center, - height: screenHeight * 0.06, - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.white, - width: _currentTabIndex == 1 ? 3.0 : 0.0, - ))), - width: screenWidth * 0.15, - child: Text( - 'Closed', - style: TextStyle( - color: _currentTabIndex == 1 - ? Colors.white - : Theme.of(context) - .secondaryHeaderColor, - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500), - ), - ), - ) - ], - ), - ), - ], - ), - ), - Expanded( - child: Container( - color: Colors.white, - child: _buildTopBar(), - ), - ), - ], - ), - ), - ), - ]), - // floatingActionButton: FloatingActionButton( - // onPressed: () { - // if (userBloc.activeUsers.length == 0) { - // } else { - // Navigator.pushNamed(context, '/user_create'); - // } - // }, - // child: Icon(Icons.add, color: Colors.white), - // backgroundColor: Theme.of(context).primaryColor, - // ), - bottomNavigationBar: BottomNavigationBarWidget()); - } - - void showAlertDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return CupertinoAlertDialog( - title: Text( - "Alert", - style: TextStyle(color: Colors.black), - ), - content: Text( - "You don't have any users, Please create user first.", - style: TextStyle(fontSize: 15.0), - ), - actions: [ - CupertinoDialogAction( - textStyle: TextStyle(color: Colors.red), - isDefaultAction: true, - onPressed: () async { - Navigator.pop(context); - }, - child: Text("Cancel")), - CupertinoDialogAction( - isDefaultAction: true, - onPressed: () { - currentBottomNavigationIndex = "4"; - Navigator.pop(context); - Navigator.pushNamed(context, "/user_create"); - }, - child: Text("Create")), - ], - ); - }); - } -} diff --git a/lib/ui/widgets/bottom_navigation_bar.dart b/lib/ui/widgets/bottom_navigation_bar.dart deleted file mode 100644 index cf8ad1e..0000000 --- a/lib/ui/widgets/bottom_navigation_bar.dart +++ /dev/null @@ -1,212 +0,0 @@ -import 'dart:core'; - -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/flutter_svg.dart'; - -class BottomNavigationBarWidget extends StatefulWidget { - @override - State createState() => _BottomNavigationBarWidgetState(); -} - -class _BottomNavigationBarWidgetState extends State { - String _currentBottomBarIndex = "0"; - @override - void initState() { - setState(() { - _currentBottomBarIndex = currentBottomNavigationIndex; - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Container( - height: screenHeight * 0.08, - //color: Colors.white, - child: Row( - children: [ - GestureDetector( - onTap: () { - if (_currentBottomBarIndex != '0') { - Navigator.pushNamedAndRemoveUntil( - context, '/dashboard', (route) => false); - setState(() { - _currentBottomBarIndex = "0"; - }); - currentBottomNavigationIndex = _currentBottomBarIndex; - } - }, - child: Container( - decoration: BoxDecoration( - color: _currentBottomBarIndex == "0" - ? bottomNavBarSelectedBGColor - : Colors.white, - borderRadius: - BorderRadius.only(topLeft: Radius.circular(30))), - width: screenWidth * 0.20, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: SvgPicture.asset( - 'assets/images/home.svg', - width: screenWidth / 15, - colorFilter: ColorFilter.mode( - _currentBottomBarIndex == "0" - ? bottomNavBarSelectedTextColor - : bottomNavBarTextColor, - BlendMode.srcIn, - ), - ), - ), - ], - ), - ), - ), - GestureDetector( - onTap: () { - if (_currentBottomBarIndex != '1') { - Navigator.pushNamedAndRemoveUntil( - context, '/accounts_list', (route) => false); - setState(() { - _currentBottomBarIndex = "1"; - }); - currentBottomNavigationIndex = _currentBottomBarIndex; - } - }, - child: Container( - color: _currentBottomBarIndex == "1" - ? bottomNavBarSelectedBGColor - : Colors.white, - width: screenWidth * 0.20, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: SvgPicture.asset( - 'assets/images/accounts.svg', - width: screenWidth / 12, - colorFilter: ColorFilter.mode( - _currentBottomBarIndex == "1" - ? bottomNavBarSelectedTextColor - : bottomNavBarTextColor, - BlendMode.srcIn, - ), - ), - ), - ], - ), - ), - ), - GestureDetector( - onTap: () { - // if (_currentBottomBarIndex != '') { - // setState(() { - // _currentBottomBarIndex = ""; - // }); - // currentBottomNavigationIndex = _currentBottomBarIndex; - // } - }, - child: Container( - color: _currentBottomBarIndex == "" - ? bottomNavBarSelectedBGColor - : Colors.white, - width: screenWidth * 0.20, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: SvgPicture.asset( - 'assets/images/search.svg', - width: screenWidth / 16, - colorFilter: ColorFilter.mode( - _currentBottomBarIndex == "" - ? bottomNavBarSelectedTextColor - : bottomNavBarTextColor, - BlendMode.srcIn, - ), - ), - ), - ], - ), - ), - ), - GestureDetector( - onTap: () { - if (_currentBottomBarIndex != '2') { - Navigator.pushNamedAndRemoveUntil( - context, '/tasks_list', (route) => false); - setState(() { - _currentBottomBarIndex = "2"; - }); - currentBottomNavigationIndex = _currentBottomBarIndex; - } - }, - child: Container( - color: _currentBottomBarIndex == "2" - ? bottomNavBarSelectedBGColor - : Colors.white, - width: screenWidth * 0.20, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: SvgPicture.asset( - 'assets/images/tasks.svg', - width: screenWidth / 18, - colorFilter: ColorFilter.mode( - _currentBottomBarIndex == "2" - ? bottomNavBarSelectedTextColor - : bottomNavBarTextColor, - BlendMode.srcIn, - ), - ), - ), - ], - ), - ), - ), - GestureDetector( - onTap: () { - if (_currentBottomBarIndex != '3') { - Navigator.pushNamedAndRemoveUntil( - context, '/more_options', (route) => false); - setState(() { - _currentBottomBarIndex = "3"; - }); - currentBottomNavigationIndex = _currentBottomBarIndex; - } - }, - child: Container( - decoration: BoxDecoration( - color: _currentBottomBarIndex == "3" - ? bottomNavBarSelectedBGColor - : Colors.white, - borderRadius: - BorderRadius.only(topRight: Radius.circular(30))), - width: screenWidth * 0.20, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: SvgPicture.asset( - 'assets/images/more.svg', - width: screenWidth / 16, - colorFilter: ColorFilter.mode( - _currentBottomBarIndex == "3" - ? bottomNavBarSelectedTextColor - : bottomNavBarTextColor, - BlendMode.srcIn, - ), - ), - ), - ], - ), - ), - ) - ], - ), - ); - } -} diff --git a/lib/ui/widgets/dashboard_count_card.dart b/lib/ui/widgets/dashboard_count_card.dart deleted file mode 100644 index ad42114..0000000 --- a/lib/ui/widgets/dashboard_count_card.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; -import 'package:flutter_svg/svg.dart'; - -class CountCard extends StatelessWidget { - final String? icon; - final Color? color; - final String? lable; - final int? count; - final String? routeName; - final int? index; - CountCard( - {this.icon, - this.color, - this.lable, - this.count, - this.routeName, - this.index}); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - currentBottomNavigationIndex = index.toString(); - Navigator.pushNamed(context, routeName!); - }, - child: Container( - width: screenWidth * 0.46, - height: screenHeight * 0.12, - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.all(Radius.circular(10.0)), - border: Border.all(color: Colors.grey.shade300, width: 2.0)), - padding: EdgeInsets.all(10.0), - child: Row( - children: [ - CircleAvatar( - radius: screenWidth / 14, - child: SvgPicture.asset( - icon!, - colorFilter: ColorFilter.mode(Colors.blueGrey[800]!, BlendMode.srcIn), - width: screenWidth / 12, - ), - backgroundColor: Colors.white, - ), - Container( - margin: EdgeInsets.only(left: 10.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: EdgeInsets.only(bottom: 5.0), - child: Text(lable!, - style: TextStyle( - color: Colors.blueGrey[800], - fontWeight: FontWeight.w500, - fontSize: lable == "Opportunities" - ? screenWidth / 30 - : screenWidth / 25)), - ), - Container( - child: Text( - count!.toString(), - style: TextStyle( - color: Colors.blueGrey[800], - fontSize: screenWidth / 15, - fontWeight: FontWeight.bold), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/lib/ui/widgets/loader.dart b/lib/ui/widgets/loader.dart deleted file mode 100644 index 8c01558..0000000 --- a/lib/ui/widgets/loader.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter/material.dart'; - -class Loader extends StatelessWidget { - Loader(); - - @override - Widget build(BuildContext context) { - return Container( - color: Colors.transparent, - width: 300.0, - height: 300.0, - child: new Padding( - padding: const EdgeInsets.all(5.0), - child: new Center(child: new CircularProgressIndicator())), - ); - } -} diff --git a/lib/ui/widgets/profile_pic_widget.dart b/lib/ui/widgets/profile_pic_widget.dart deleted file mode 100644 index 6e20d0f..0000000 --- a/lib/ui/widgets/profile_pic_widget.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class ProfilePicViewWidget extends StatelessWidget { - final List profilePicsList; - ProfilePicViewWidget(this.profilePicsList); - - List buildProfile() { - List tagWidgets = []; - for (int i = 0; i < profilePicsList.length; i++) { - tagWidgets.add(createProfile(i)); - } - return tagWidgets; - } - - Widget createProfile(profilePicIndex) { - return Container( - margin: EdgeInsets.only(bottom: 5.0), - padding: EdgeInsets.symmetric(horizontal: 1.0, vertical: 2.0), - child: profilePicsList[profilePicIndex] != null && - profilePicsList[profilePicIndex] != "" && - Uri.parse(profilePicsList[profilePicIndex]).isAbsolute - ? CircleAvatar( - radius: screenWidth / 20, - backgroundImage: NetworkImage(profilePicsList[profilePicIndex]), - ) - : CircleAvatar( - radius: screenWidth / 20, - child: Text(profilePicsList[profilePicIndex], - style: TextStyle( - color: Colors.white, fontWeight: FontWeight.bold)), - backgroundColor: randomColor.randomColor( - colorBrightness: ColorBrightness.dark), - ), - ); - } - - @override - Widget build(BuildContext context) { - return SingleChildScrollView( - child: Wrap( - alignment: WrapAlignment.start, - spacing: 5.0, - direction: Axis.horizontal, - children: buildProfile(), - ), - ); - } -} diff --git a/lib/ui/widgets/recent_card_widget.dart b/lib/ui/widgets/recent_card_widget.dart deleted file mode 100644 index 78271c0..0000000 --- a/lib/ui/widgets/recent_card_widget.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:bottle_crm/ui/widgets/tags_widget.dart'; -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class RecentCardWidget extends StatelessWidget { - final String? source; - final String? name; - final String? date; - final String? city; - final String? email; - final String? photoUrl; - final String? createdBy; - final List? tags; - - RecentCardWidget( - {this.source, - this.name, - this.date, - this.city, - this.email, - this.photoUrl, - this.createdBy, - this.tags}); - - @override - Widget build(BuildContext context) { - return Container( - // height: screenHeight * 0.09, - //color: Colors.white, - padding: EdgeInsets.all(10.0), - margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), - decoration: BoxDecoration( - border: Border.all(width: 1.0, color: Colors.grey), - borderRadius: BorderRadius.all(Radius.circular(5.0)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: screenWidth * 0.5, - child: Text(name!.capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.black87, - fontWeight: FontWeight.w600, - fontSize: screenWidth / 21))), - Container( - width: screenWidth * 0.3, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - photoUrl != "" - ? CircleAvatar( - radius: screenWidth / 28, - backgroundImage: NetworkImage(photoUrl!), - ) - : CircleAvatar( - radius: screenWidth / 30, - backgroundColor: Theme.of(context).primaryColor, - child: Text( - createdBy![0].allInCaps, - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold), - ), - ), - SizedBox(width: 5.0), - Text(createdBy!.capitalizeFirstofEach(), - style: TextStyle( - overflow: TextOverflow.ellipsis, - color: Colors.blueGrey[800], - fontWeight: FontWeight.w500, - fontSize: screenWidth / 25)) - ], - ), - ) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container(width: screenWidth * 0.5, child: TagViewWidget(tags!)), - Text(date!, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: bottomNavBarTextColor, - fontSize: screenWidth / 26)), - ], - ), - ], - ), - ); - } -} diff --git a/lib/ui/widgets/tags_widget.dart b/lib/ui/widgets/tags_widget.dart deleted file mode 100644 index b8efd9e..0000000 --- a/lib/ui/widgets/tags_widget.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:bottle_crm/utils/utils.dart'; - -class TagViewWidget extends StatelessWidget { - final List tags; - TagViewWidget(this.tags); - - List buildTags() { - List tagWidgets = []; - for (int i = 0; i < tags.length; i++) { - tagWidgets.add(createTag(i)); - } - return tagWidgets; - } - - Widget createTag(tagIndex) { - return Container( - margin: EdgeInsets.only(bottom: 5.0), - padding: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0), - color: randomColor.randomColor(colorBrightness: ColorBrightness.light), - child: Text( - tags[tagIndex]['name'], - style: TextStyle(color: Colors.white, fontSize: 12.0), - ), - ); - } - - @override - Widget build(BuildContext context) { - return SingleChildScrollView( - child: Wrap( - alignment: WrapAlignment.start, - spacing: 5.0, - direction: Axis.horizontal, - children: buildTags(), - ), - ); - } -} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart deleted file mode 100644 index af6d60a..0000000 --- a/lib/utils/utils.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'dart:io'; -import 'dart:math'; - -import 'package:bottle_crm/bloc/account_bloc.dart'; -import 'package:bottle_crm/bloc/case_bloc.dart'; -import 'package:bottle_crm/bloc/contact_bloc.dart'; -import 'package:bottle_crm/bloc/dashboard_bloc.dart'; -import 'package:bottle_crm/bloc/event_bloc.dart'; -import 'package:bottle_crm/bloc/lead_bloc.dart'; -import 'package:bottle_crm/bloc/opportunity_bloc.dart'; -import 'package:bottle_crm/bloc/setting_bloc.dart'; -import 'package:bottle_crm/bloc/task_bloc.dart'; -import 'package:bottle_crm/bloc/team_bloc.dart'; -import 'package:bottle_crm/bloc/user_bloc.dart'; -import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:flutter_styled_toast/flutter_styled_toast.dart'; - -var screenWidth; -var screenHeight; -// Color submitButtonColor = Color.fromRGBO(75, 153, 90, 1); -// Color bottomNavBarSelectedBGColor = Color.fromRGBO(219, 232, 249, 1); -// Color bottomNavBarSelectedTextColor = Color.fromRGBO(15, 36, 62, 1); -// Color bottomNavBarTextColor = Color.fromRGBO(75, 75, 78, 1); -String currentBottomNavigationIndex = "0"; -String currentTopBarModuleName = "Dashboard"; -Color bottomNavBarTextColor = Color.fromRGBO(75, 75, 78, 1); -Color submitButtonColor = Color.fromRGBO(75, 153, 90, 1); -Color bottomNavBarSelectedBGColor = Color.fromRGBO(219, 232, 249, 1); -Color bottomNavBarSelectedTextColor = Color.fromRGBO(15, 36, 62, 1); - -// Simple random color generator to replace RandomColor package -class SimpleRandomColor { - static final Random _random = Random(); - - Color randomColor({ColorBrightness? colorBrightness}) { - if (colorBrightness == ColorBrightness.light) { - // Generate lighter colors - return Color.fromRGBO( - _random.nextInt(128) + 128, // 128-255 - _random.nextInt(128) + 128, // 128-255 - _random.nextInt(128) + 128, // 128-255 - 1.0, - ); - } else { - // Generate any random color - return Color.fromRGBO( - _random.nextInt(256), - _random.nextInt(256), - _random.nextInt(256), - 1.0, - ); - } - } -} - -enum ColorBrightness { light, dark } - -SimpleRandomColor randomColor = SimpleRandomColor(); - -fetchRequiredData() async { - print("fetching data ▁ ▂ ▃ ▄ ▅ ▆"); - // Profile data already fetched during login - no need to fetch again - await dashboardBloc.fetchDashboardDetails(); - await leadBloc.fetchLeads(); - await accountBloc.fetchAccounts(); - await contactBloc.fetchContacts(); - await opportunityBloc.fetchOpportunities(); - await caseBloc.fetchCases(); - await userBloc.fetchUsers(); - await taskBloc.fetchTasks(); - await teamBloc.fetchTeams(); - await eventBloc.fetchEvents(); - await settingsBloc.fetchApiSettings(); - print("✓ data fetched successfully"); -} - -OutlineInputBorder boxBorder() { - return OutlineInputBorder( - // borderRadius: BorderRadius.all(Radius.circular(15)), - borderSide: BorderSide(width: 0, color: Colors.white), - ); -} - -extension CapExtension on String { - String get inCaps => '${this[0].toUpperCase()}${this.substring(1)}'; - String get allInCaps => this.toUpperCase(); - String capitalizeFirstofEach() => - this.split(" ").map((str) => str.inCaps).join(" "); -} - -DateTime? currentBackPressTime; -Future onWillPop() { - DateTime now = DateTime.now(); - if (currentBackPressTime == null || - now.difference(currentBackPressTime!) > Duration(seconds: 2)) { - currentBackPressTime = now; - Fluttertoast.showToast(msg: 'Press again to close Bottle CRM'); - return Future.value(false); - } - exit(0); -} - -// showToast(message) { -// Fluttertoast.showToast( -// msg: message, -// toastLength: Toast.LENGTH_LONG, -// gravity: ToastGravity.CENTER, -// timeInSecForIosWeb: 1, -// backgroundColor: Colors.blue, -// textColor: Colors.white, -// fontSize: screenWidth / 26, -// ); -// } - -showToaster(message, context) { - showToast( - message, - context: context, - animation: StyledToastAnimation.scale, - reverseAnimation: StyledToastAnimation.fade, - position: StyledToastPosition.bottom, - animDuration: Duration(seconds: 1), - duration: Duration(seconds: 4), - curve: Curves.elasticOut, - reverseCurve: Curves.linear, - ); -} - -TextStyle buildLableTextStyle() { - return TextStyle( - fontSize: screenWidth / 25, - fontWeight: FontWeight.w500, - color: Colors.blueGrey); -} diff --git a/lib/utils/validations.dart b/lib/utils/validations.dart deleted file mode 100644 index 1a528f9..0000000 --- a/lib/utils/validations.dart +++ /dev/null @@ -1,18 +0,0 @@ -class FieldValidators { - static String? emailFieldValidation(String value) { - if (value.isEmpty) return "Please Enter Email "; - - RegExp regExp = new RegExp( - r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$"); - - if (value.isNotEmpty && !regExp.hasMatch(value)) { - return "Please Enter Valid Email "; - } - return null; - } - - static String? passwordValidation(String value) { - if (value.isEmpty) return "Please Enter Password"; - return null; - } -} diff --git a/linux/.gitignore b/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt new file mode 100644 index 0000000..32e0f2c --- /dev/null +++ b/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "bottlecrm") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "io.bottlecrm") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/linux/flutter/CMakeLists.txt b/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..e71a16d --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/linux/flutter/generated_plugin_registrant.h b/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..2e1de87 --- /dev/null +++ b/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/runner/CMakeLists.txt b/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/linux/runner/main.cc b/linux/runner/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc new file mode 100644 index 0000000..b0235cd --- /dev/null +++ b/linux/runner/my_application.cc @@ -0,0 +1,130 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "bottlecrm"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "bottlecrm"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/linux/runner/my_application.h b/linux/runner/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/macos/.gitignore b/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..22724f6 --- /dev/null +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,16 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import google_sign_in_ios +import package_info_plus +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..edaec34 --- /dev/null +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* bottlecrm.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "bottlecrm.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* bottlecrm.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* bottlecrm.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bottlecrm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bottlecrm"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bottlecrm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bottlecrm"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/bottlecrm.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/bottlecrm"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..3a881c0 --- /dev/null +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..b3c1761 --- /dev/null +++ b/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 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 literal 0 HcmV?d00001 diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..56a5245 --- /dev/null +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = bottlecrm + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = io.bottlecrm + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/macos/Runner/Configs/Debug.xcconfig b/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Release.xcconfig b/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/macos/Runner/Configs/Warnings.xcconfig b/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/macos/Runner/MainFlutterWindow.swift b/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/macos/RunnerTests/RunnerTests.swift b/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..65d84a5 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,562 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" + url: "https://pub.dev" + source: hosted + version: "0.14.4" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a + url: "https://pub.dev" + source: hosted + version: "10.8.0" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454" + url: "https://pub.dev" + source: hosted + version: "0.3.3+1" + google_sign_in: + dependency: "direct main" + description: + name: google_sign_in + sha256: "939a8b58f84c4053811b8c1bc9adbcb59449a15b37958264bbf60020698cca0e" + url: "https://pub.dev" + source: hosted + version: "7.1.1" + google_sign_in_android: + dependency: transitive + description: + name: google_sign_in_android + sha256: f256b8f0e6c09d135c166fe20b25256e24d60fe1a72e6bdc112a200bd0d555b4 + url: "https://pub.dev" + source: hosted + version: "7.0.3" + google_sign_in_ios: + dependency: transitive + description: + name: google_sign_in_ios + sha256: c7ee744ebbcd98353966dbdee735d4fca085226f6bf725c6bea8a5c8fe0055bc + url: "https://pub.dev" + source: hosted + version: "6.1.0" + google_sign_in_platform_interface: + dependency: transitive + description: + name: google_sign_in_platform_interface + sha256: "8736443134d2cccadd4f228d600177cb3947e36683466a6ab96877ce6932885a" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + google_sign_in_web: + dependency: transitive + description: + name: google_sign_in_web + sha256: "09ac306b2787b48f19c857b9f93375b654f774643c75bd6a1a078c85f4f7b468" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + image: + dependency: transitive + description: + name: image + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" + url: "https://pub.dev" + source: hosted + version: "4.5.4" + intl: + dependency: "direct main" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + jwt_decoder: + dependency: "direct main" + description: + name: jwt_decoder + sha256: "54774aebf83f2923b99e6416b4ea915d47af3bde56884eb622de85feabbc559f" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 + url: "https://pub.dev" + source: hosted + version: "6.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + url: "https://pub.dev" + source: hosted + version: "8.3.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + url: "https://pub.dev" + source: hosted + version: "6.0.3" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" + url: "https://pub.dev" + source: hosted + version: "2.4.10" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" + url: "https://pub.dev" + source: hosted + version: "5.14.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.8.1 <4.0.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 157c967..931415b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,50 +1,53 @@ name: bottle_crm -description: A new Flutter project. +description: "CRM for everyone." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev -publish_to: 'none' - -version: 1.0.16+16 +version: 1.0.0+9 environment: - sdk: '>=3.0.0 <4.0.0' + sdk: ^3.8.1 dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.8 - http: ^1.2.2 - file_picker: ^10.2.0 - connectivity_plus: ^6.1.0 - flutter_svg: ^2.0.16 - intl: ^0.20.2 - shared_preferences: ^2.3.3 - fluttertoast: ^8.2.8 - flutter_styled_toast: ^2.2.1 - dropdown_search: ^6.0.2 - textfield_tags: ^3.0.1 - multiselect_formfield: ^0.1.7 - flutter_quill: ^11.4.2 - firebase_analytics: ^12.0.0 - firebase_core: ^4.0.0 - flutter_swipe_detector: ^2.0.0 - google_sign_in: ^6.2.2 - - -flutter_icons: - android: "launcher_icon" - ios: true - image_path: "assets/images/new_logo.png" + http: ^1.1.0 + google_sign_in: ^7.1.1 + shared_preferences: ^2.2.2 + jwt_decoder: ^2.0.1 + font_awesome_flutter: ^10.7.0 + intl: ^0.19.0 + package_info_plus: ^8.0.2 dev_dependencies: flutter_test: sdk: flutter - flutter_launcher_icons: ^0.14.1 + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^6.0.0 + flutter_launcher_icons: "^0.14.4" + +flutter_launcher_icons: + android: "launcher_icon" + ios: true + image_path: "assets/icon/icon.png" + min_sdk_android: 31 # android min sdk Android 12 (API 31) + remove_alpha_ios: true # remove alpha channel from iOS icons, default false + +# The following section is specific to Flutter packages. flutter: uses-material-design: true + # To add assets to your application, add an assets section, like this: assets: + - assets/icon/ - assets/images/ diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index d130c5b..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:bottle_crm/bloc/auth_bloc.dart'; -import 'package:bottle_crm/utils/validations.dart'; -import 'package:flutter_test/flutter_test.dart'; - -// import 'package:mobile2/main.dart'; - -void main() { - group("Google Login", () { - test("Google Login should handle authentication", () async{ - Map result = await authBloc.googleLogin(); - expect(result.containsKey('error'), true); - }); - - test("Password validation should still work", () { - var result = FieldValidators.passwordValidation(""); - expect("Please Enter Password", result); - }); - }); - // testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // // Build our app and trigger a frame. - // await tester.pumpWidget(MyApp()); - - // // Verify that our counter starts at 0. - // expect(find.text('0'), findsOneWidget); - // expect(find.text('1'), findsNothing); - - // // Tap the '+' icon and trigger a frame. - // await tester.tap(find.byIcon(Icons.add)); - // await tester.pump(); - - // // Verify that our counter has incremented. - // expect(find.text('0'), findsNothing); - // expect(find.text('1'), findsOneWidget); - // }); -} diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 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 MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..1f751ad --- /dev/null +++ b/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + bottlecrm + + + + + + diff --git a/web/manifest.json b/web/manifest.json new file mode 100644 index 0000000..51cf1a6 --- /dev/null +++ b/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "bottlecrm", + "short_name": "bottlecrm", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt new file mode 100644 index 0000000..dec64d9 --- /dev/null +++ b/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(bottlecrm LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "bottlecrm") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..8b6d468 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void RegisterPlugins(flutter::PluginRegistry* registry) { +} diff --git a/windows/flutter/generated_plugin_registrant.h b/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..b93c4c3 --- /dev/null +++ b/windows/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc new file mode 100644 index 0000000..7f090ce --- /dev/null +++ b/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "bottlecrm" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "bottlecrm" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "bottlecrm.exe" "\0" + VALUE "ProductName", "bottlecrm" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp new file mode 100644 index 0000000..35b1721 --- /dev/null +++ b/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"bottlecrm", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/windows/runner/resource.h b/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 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 literal 0 HcmV?d00001 diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..153653e --- /dev/null +++ b/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/windows/runner/utils.h b/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_