diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies
index 130f7a6..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":"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-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 37b1568..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
@@ -46,3 +43,71 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
+
+# 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
+
+# Claude AI Assistant
+.claude/
+*.claude.json
+
+# 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*
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..f434879
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,137 @@
+# 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 c100630..2e7d540 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,561 @@
-# BottleCRM
+# BottleCRM Mobile
-Free CRM for startups and enterprises.
+
+
+
+
+
+
-# build
+[](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
+
+### ๐จ 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
+
+## ๐ Requirements
+
+### 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
+
+### 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)
+
+### Development Tools
+- **Android SDK**: For Android development
+- **Xcode**: For iOS development (macOS only)
+- **CocoaPods**: iOS dependency management
+
+## ๐ Getting Started
+
+### ๐ฑ For End Users
+
+**Download the app directly from Google Play Store:**
+
+
+
+[](https://play.google.com/store/apps/details?id=io.bottlecrm)
+
+*Package ID: `io.bottlecrm`*
+
+
+
+### ๐จโ๐ป 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 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
+
+# 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 & Deployment
+
+### Android Builds
+
+```bash
+# Clean and prepare
+flutter clean
+flutter pub get
+
+# 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
+
+```
+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
+ โโโ ...
+```
+
+### Key Architecture Components
+
+#### 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...
+}
+```
+
+#### 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
+
+#### 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
+
+### 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 application uses environment-based API URLs configured in `lib/config/api_config.dart`:
+
+```dart
+// Development (debug builds)
+static const String _developmentUrl = 'https://b2ad5166b831.ngrok-free.app';
+
+// 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
+ ```
+
+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 build appbundle
-flutter build apk
+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
+
+---
+
+
+
+**BottleCRM Mobile** - Free CRM for startups and enterprises
+
+Made with โค๏ธ using Flutter
+
+
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/google-services.json b/android/app/google-services.json
deleted file mode 100644
index 642c4df..0000000
--- a/android/app/google-services.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "project_info": {
- "project_number": "74115878447",
- "project_id": "bottle-crm-10074",
- "storage_bucket": "bottle-crm-10074.appspot.com"
- },
- "client": [
- {
- "client_info": {
- "mobilesdk_app_id": "1:74115878447:android:858fb769df26bb2c5900da",
- "android_client_info": {
- "package_name": "io.bottlecrm"
- }
- },
- "oauth_client": [
- {
- "client_id": "74115878447-0r10i3hk3mma0u2vaenbsbtvvtud5sv5.apps.googleusercontent.com",
- "client_type": 3
- }
- ],
- "api_key": [
- {
- "current_key": "AIzaSyD8es-uwk_IlZsuHWlEwfiEZfsrENKXRgA"
- }
- ],
- "services": {
- "appinvite_service": {
- "other_platform_oauth_client": [
- {
- "client_id": "74115878447-0r10i3hk3mma0u2vaenbsbtvvtud5sv5.apps.googleusercontent.com",
- "client_type": 3
- }
- ]
- }
- }
- }
- ],
- "configuration_version": "1"
-}
\ No newline at end of file
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 0c1124c..51cace0 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png
index 84e1269..52c7931 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
index 4881b68..a5d2ddf 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ
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 3fbc6ca..45e4a7f 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ
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 ab8c484..0eea747 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ
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 0000000..fbac8d9
Binary files /dev/null and b/assets/icon/icon.png differ
diff --git a/assets/images/Icon_edit_color.svg b/assets/images/Icon_edit_color.svg
deleted file mode 100644
index 7113be8..0000000
--- a/assets/images/Icon_edit_color.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
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 2adb050..0000000
Binary files a/assets/images/bg-image-blue.jpg and /dev/null differ
diff --git a/assets/images/bg-image.png b/assets/images/bg-image.png
deleted file mode 100644
index 49d6742..0000000
Binary files a/assets/images/bg-image.png and /dev/null differ
diff --git a/assets/images/cases.svg b/assets/images/cases.svg
deleted file mode 100644
index bbfe30b..0000000
--- a/assets/images/cases.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
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 4bc4e1d..0000000
Binary files a/assets/images/google-icon.png and /dev/null differ
diff --git a/assets/images/home.svg b/assets/images/home.svg
deleted file mode 100644
index 4c6204e..0000000
--- a/assets/images/home.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
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 d3ee457..0000000
Binary files a/assets/images/new_logo.png and /dev/null differ
diff --git a/assets/images/opportunities.svg b/assets/images/opportunities.svg
deleted file mode 100644
index 6987a65..0000000
--- a/assets/images/opportunities.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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 6f6fecc..0000000
Binary files a/assets/images/skype.png and /dev/null differ
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 b9c83c6..54f7c8b 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ
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 bb03bf8..515c031 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
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 4884bd8..a2efca6 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
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 fa4a858..999e6e4 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
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 c4fbdef..add7e42 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
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 90aee90..9db4e88 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
index cf1255b..0098d6e 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
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 4884bd8..a2efca6 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
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 44d5c44..ee28bd0 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
index 3d5a1be..2231691 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
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 0000000..faccfa8
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ
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 0000000..e8a4b62
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ
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 0000000..f3aaf10
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
new file mode 100644
index 0000000..1ceac7c
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
index 3d5a1be..2231691 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
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 69f5fde..c0cffe2 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
new file mode 100644
index 0000000..6672cdd
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ
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 0000000..586a567
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ
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 a6c7c25..eaefaf8 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
index 6d57b36..37006b2 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
index 7d1e973..436ed14 100644
Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
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 2319b1a..0000000
--- a/lib/bloc/auth_bloc.dart
+++ /dev/null
@@ -1,151 +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';
-
-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 login(data) async {
- try {
- Map result = {};
- final SharedPreferences preferences =
- await SharedPreferences.getInstance();
- await CrmService().userLogin(data).then((response) async {
- var res = (json.decode(response.body));
- if (res['error'] == false) {
- _authToken = "JWT " + res['token'];
- preferences.setString("authToken", _authToken!);
- result = res;
- } else {
- result = res;
- }
- }).catchError((onError) {
- print("login error>> $onError");
- result = {"status": "error", "message": onError};
- });
- return result;
- } catch (e) {}
- }
-
- 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) {
- }
-
- }
-}
-
-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
new file mode 100644
index 0000000..c3c4d6f
--- /dev/null
+++ b/lib/config/api_config.dart
@@ -0,0 +1,83 @@
+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 19809ca..eaedfb1 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,129 +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/authentication/forgot_password.dart';
-import 'package:bottle_crm/ui/screens/authentication/login.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/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) => Login(),
- '/register': (BuildContext context) => Register(),
- '/forgot_password': (BuildContext context) => ForgotPassword(),
- '/change_password': (BuildContext context) => ChangePassword(),
- '/profile': (BuildContext context) => Profile(),
- '/dashboard': (BuildContext context) => 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(),
- '/companies_List': (BuildContext context) => CompaniesList(),
- '/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 64acd5d..0000000
--- a/lib/model/organization.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-class Organization {
- int? id;
- String? name;
-
- Organization({this.id, this.name});
-
- Organization.fromJson(Map data) {
- this.id = data['id'] != null ? data['id'] : 0;
- this.name = data['name'] != null ? data['name'] : "";
- }
-
- toJson() {
- return {'id': id, 'name': name};
- }
-}
diff --git a/lib/model/profile.dart b/lib/model/profile.dart
deleted file mode 100644
index 3a484f9..0000000
--- a/lib/model/profile.dart
+++ /dev/null
@@ -1,75 +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) {
- this.id = profile['user_details']['id'] != null
- ? profile['user_details']['id']
- : 0;
- 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.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