diff --git a/apps/mobile/prototypes/client_mobile_application/.gitignore b/apps/mobile/prototypes/client_mobile_application/.gitignore deleted file mode 100644 index 3820a95c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ -/coverage/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/apps/mobile/prototypes/client_mobile_application/.metadata b/apps/mobile/prototypes/client_mobile_application/.metadata deleted file mode 100644 index 2c6187b3..00000000 --- a/apps/mobile/prototypes/client_mobile_application/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "b45fa18946ecc2d9b4009952c636ba7e2ffbb787" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: android - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: ios - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: linux - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: macos - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: web - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: windows - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/apps/mobile/prototypes/client_mobile_application/README.md b/apps/mobile/prototypes/client_mobile_application/README.md deleted file mode 100644 index edb5b95e..00000000 --- a/apps/mobile/prototypes/client_mobile_application/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# client_app_mvp - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/apps/mobile/prototypes/client_mobile_application/analysis_options.yaml b/apps/mobile/prototypes/client_mobile_application/analysis_options.yaml deleted file mode 100644 index 0d290213..00000000 --- a/apps/mobile/prototypes/client_mobile_application/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# 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/apps/mobile/prototypes/client_mobile_application/android/.gitignore b/apps/mobile/prototypes/client_mobile_application/android/.gitignore deleted file mode 100644 index be3943c9..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java -.cxx/ - -# Remember to never publicly share your keystore. -# See https://flutter.dev/to/reference-keystore -key.properties -**/*.keystore -**/*.jks diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/build.gradle.kts b/apps/mobile/prototypes/client_mobile_application/android/app/build.gradle.kts deleted file mode 100644 index 950967ca..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/build.gradle.kts +++ /dev/null @@ -1,45 +0,0 @@ -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") -} - -android { - namespace = "com.example.client_app_mvp" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.client_app_mvp" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName - } - - 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") - } - } -} - -flutter { - source = "../.." -} diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/google-services.json b/apps/mobile/prototypes/client_mobile_application/android/app/google-services.json deleted file mode 100644 index d2dd9ffe..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/google-services.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "project_info": { - "project_number": "717206318340", - "project_id": "krow-apps", - "storage_bucket": "krow-apps.firebasestorage.app" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:717206318340:android:b0bff06f9967d8678af451", - "android_client_info": { - "package_name": "com.example.client_app_mvp" - } - }, - "oauth_client": [ - { - "client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com", - "client_type": 3 - } - ] - } - } - }, - { - "client_info": { - "mobilesdk_app_id": "1:717206318340:android:d3eac8c3774905e08af451", - "android_client_info": { - "package_name": "com.example.staff_app_mvp" - } - }, - "oauth_client": [ - { - "client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com", - "client_type": 3 - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/debug/AndroidManifest.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/AndroidManifest.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index ffae6d58..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/kotlin/com/example/client_app_mvp/MainActivity.kt b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/kotlin/com/example/client_app_mvp/MainActivity.kt deleted file mode 100644 index 34dfb450..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/kotlin/com/example/client_app_mvp/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.client_app_mvp - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity : FlutterActivity() diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/drawable-v21/launch_background.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/drawable/launch_background.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-hdpi/launcher_icon.png deleted file mode 100644 index 55840fad..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-hdpi/launcher_icon.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-mdpi/launcher_icon.png deleted file mode 100644 index 25a22f92..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-mdpi/launcher_icon.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d43914..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png deleted file mode 100644 index 9a20688e..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d3..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png deleted file mode 100644 index 1f506d87..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372ee..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png deleted file mode 100644 index c2c87b7d..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/values-night/styles.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be7..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/values/styles.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef880..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/app/src/profile/AndroidManifest.xml b/apps/mobile/prototypes/client_mobile_application/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/android/build.gradle.kts b/apps/mobile/prototypes/client_mobile_application/android/build.gradle.kts deleted file mode 100644 index dbee657b..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/build.gradle.kts +++ /dev/null @@ -1,24 +0,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/apps/mobile/prototypes/client_mobile_application/android/gradle.properties b/apps/mobile/prototypes/client_mobile_application/android/gradle.properties deleted file mode 100644 index fbee1d8c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true diff --git a/apps/mobile/prototypes/client_mobile_application/android/gradle/wrapper/gradle-wrapper.properties b/apps/mobile/prototypes/client_mobile_application/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e4ef43fb..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/apps/mobile/prototypes/client_mobile_application/android/settings.gradle.kts b/apps/mobile/prototypes/client_mobile_application/android/settings.gradle.kts deleted file mode 100644 index e4e86fb6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/android/settings.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -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.11.1" apply false - id("org.jetbrains.kotlin.android") version "2.2.20" apply false - id("com.google.gms.google-services") version "4.4.2" apply false -} - -include(":app") diff --git a/apps/mobile/prototypes/client_mobile_application/assets/logo.png b/apps/mobile/prototypes/client_mobile_application/assets/logo.png deleted file mode 100644 index b7781d5a..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/assets/logo.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/.gitignore b/apps/mobile/prototypes/client_mobile_application/ios/.gitignore deleted file mode 100644 index 7a7f9873..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Flutter/AppFrameworkInfo.plist b/apps/mobile/prototypes/client_mobile_application/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 1dc6cf76..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 13.0 - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Flutter/Debug.xcconfig b/apps/mobile/prototypes/client_mobile_application/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Flutter/Release.xcconfig b/apps/mobile/prototypes/client_mobile_application/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Podfile b/apps/mobile/prototypes/client_mobile_application/ios/Podfile deleted file mode 100644 index 620e46eb..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '13.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! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.pbxproj b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 92b8f353..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,728 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - 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 */; }; - 59A242D46CCC2B41A5A2C541 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD5AC650E4AD66A8AC1F1833 /* Pods_Runner.framework */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 76284B4CE5310321526352FD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93FA99887D920E203CE2CDBC /* Pods_RunnerTests.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; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* 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 = ""; }; - 50734491C8F4091FC4215298 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 6B4A6F53289C89C876C48A46 /* 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 = ""; }; - 6D7BF6C00FBA636F126BBD33 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.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 = ""; }; - 93FA99887D920E203CE2CDBC /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 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 = ""; }; - B701E0489709E5092E6A038C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - BD5AC650E4AD66A8AC1F1833 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C4A6F6F8B46779D11DEEA3E7 /* 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 = ""; }; - F4AA850DEDC9D26C59B80E5F /* 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 = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 59A242D46CCC2B41A5A2C541 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - F86625E7251DC5F34D5E3557 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 76284B4CE5310321526352FD /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 09914133214C1E3120D3D9EE /* Frameworks */ = { - isa = PBXGroup; - children = ( - BD5AC650E4AD66A8AC1F1833 /* Pods_Runner.framework */, - 93FA99887D920E203CE2CDBC /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 172627A77D8C2EB68F8D116E /* Pods */ = { - isa = PBXGroup; - children = ( - F4AA850DEDC9D26C59B80E5F /* Pods-Runner.debug.xcconfig */, - 6B4A6F53289C89C876C48A46 /* Pods-Runner.release.xcconfig */, - C4A6F6F8B46779D11DEEA3E7 /* Pods-Runner.profile.xcconfig */, - 6D7BF6C00FBA636F126BBD33 /* Pods-RunnerTests.debug.xcconfig */, - 50734491C8F4091FC4215298 /* Pods-RunnerTests.release.xcconfig */, - B701E0489709E5092E6A038C /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - 172627A77D8C2EB68F8D116E /* Pods */, - 09914133214C1E3120D3D9EE /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - AE1567838935F36DA48C52B1 /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - F86625E7251DC5F34D5E3557 /* Frameworks */, - ); - 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 = ( - A06687346091B014AF063603 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 4F27457BBFA344CA19B6713C /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - 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; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 4F27457BBFA344CA19B6713C /* [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; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - A06687346091B014AF063603 /* [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; - }; - AE1567838935F36DA48C52B1 /* [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-RunnerTests-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; - }; -/* 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; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* 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; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - 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++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - 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; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6D7BF6C00FBA636F126BBD33 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.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; - baseConfigurationReference = 50734491C8F4091FC4215298 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.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; - baseConfigurationReference = B701E0489709E5092E6A038C /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.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++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - 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; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - 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++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - 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; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* 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 = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index e3773d42..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/contents.xcworkspacedata b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/AppDelegate.swift b/apps/mobile/prototypes/client_mobile_application/ios/Runner/AppDelegate.swift deleted file mode 100644 index 62666446..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Flutter -import UIKit - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d0d98aa1..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1 +0,0 @@ -{"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/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index d0e33935..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index c7df9ee5..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index d7837429..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 7b90a096..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 77ea8ae1..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index 8d2c1ab0..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 096e0c97..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index d7837429..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 65900f5b..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index eb73d40b..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png deleted file mode 100644 index acd25220..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png deleted file mode 100644 index b876168c..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index bd510694..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index 47ef28c6..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index eb73d40b..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 7de91503..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png deleted file mode 100644 index ecc091c1..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png deleted file mode 100644 index 5f61c747..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index dd66582e..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index acc8c818..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 2551480b..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Base.lproj/LaunchScreen.storyboard b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Base.lproj/Main.storyboard b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Info.plist b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Info.plist deleted file mode 100644 index cf25321e..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Client App Mvp - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - client_app_mvp - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Runner-Bridging-Header.h b/apps/mobile/prototypes/client_mobile_application/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/apps/mobile/prototypes/client_mobile_application/ios/RunnerTests/RunnerTests.swift b/apps/mobile/prototypes/client_mobile_application/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b1..00000000 --- a/apps/mobile/prototypes/client_mobile_application/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -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/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/config.json b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/config.json deleted file mode 100644 index e37ed06f..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "A set of guides for interacting with the generated firebase dataconnect sdk", - "mcpServers": { - "firebase": { - "command": "npx", - "args": ["-y", "firebase-tools@latest", "experimental:mcp"] - } - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/setup.md b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/setup.md deleted file mode 100644 index 4a3737fe..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/setup.md +++ /dev/null @@ -1,15 +0,0 @@ -# Setup - -This guide will walk you through setting up your environment to use the Firebase Data Connect SDK. Mostly using -documentation listed [here](https://firebase.google.com/docs/flutter/setup?platform=ios#install-cli-tools). - -1. Make sure you have the latest Firebase CLI tools installed. Follow the instructions [here](https://firebase.google.com/docs/cli#setup_update_cli) to install. -2. Log into your Firebase account: -```sh -firebase login -``` -3. Install the FlutterFire CLI by running the following command from any directory: -```sh -dart pub global activate flutterfire_cli -``` -4. Make sure the user has initialized Firebase already based on the instructions [here](https://firebase.google.com/docs/flutter/setup?platform=ios#initialize-firebase). diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/usage.md b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/usage.md deleted file mode 100644 index 28407bc2..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/.guides/usage.md +++ /dev/null @@ -1,31 +0,0 @@ -# Basic Usage - -```dart -ExampleConnector.instance.CreateMovie(createMovieVariables).execute(); -ExampleConnector.instance.UpsertUser(upsertUserVariables).execute(); -ExampleConnector.instance.AddReview(addReviewVariables).execute(); -ExampleConnector.instance.DeleteReview(deleteReviewVariables).execute(); -ExampleConnector.instance.ListMovies().execute(); -ExampleConnector.instance.ListUsers().execute(); -ExampleConnector.instance.ListUserReviews().execute(); -ExampleConnector.instance.GetMovieById(getMovieByIdVariables).execute(); -ExampleConnector.instance.SearchMovie(searchMovieVariables).execute(); - -``` - -## Optional Fields - -Some operations may have optional fields. In these cases, the Flutter SDK exposes a builder method, and will have to be set separately. - -Optional fields can be discovered based on classes that have `Optional` object types. - -This is an example of a mutation with an optional field: - -```dart -await ExampleConnector.instance.SearchMovie({ ... }) -.titleInput(...) -.execute(); -``` - -Note: the above example is a mutation, but the same logic applies to query operations as well. Additionally, `createMovie` is an example, and may not be available to the user. - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/README.md b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/README.md deleted file mode 100644 index 2104decc..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/README.md +++ /dev/null @@ -1,446 +0,0 @@ -# dataconnect_generated SDK - -## Installation -```sh -flutter pub get firebase_data_connect -flutterfire configure -``` -For more information, see [Flutter for Firebase installation documentation](https://firebase.google.com/docs/data-connect/flutter-sdk#use-core). - -## Data Connect instance -Each connector creates a static class, with an instance of the `DataConnect` class that can be used to connect to your Data Connect backend and call operations. - -### Connecting to the emulator - -```dart -String host = 'localhost'; // or your host name -int port = 9399; // or your port number -ExampleConnector.instance.dataConnect.useDataConnectEmulator(host, port); -``` - -You can also call queries and mutations by using the connector class. -## Queries - -### ListMovies -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.listMovies().execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.listMovies(); -ListMoviesData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.listMovies().ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### ListUsers -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.listUsers().execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.listUsers(); -ListUsersData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.listUsers().ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### ListUserReviews -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.listUserReviews().execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.listUserReviews(); -ListUserReviewsData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.listUserReviews().ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### GetMovieById -#### Required Arguments -```dart -String id = ...; -ExampleConnector.instance.getMovieById( - id: id, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.getMovieById( - id: id, -); -GetMovieByIdData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String id = ...; - -final ref = ExampleConnector.instance.getMovieById( - id: id, -).ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### SearchMovie -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.searchMovie().execute(); -``` - -#### Optional Arguments -We return a builder for each query. For SearchMovie, we created `SearchMovieBuilder`. For queries and mutations with optional parameters, we return a builder class. -The builder pattern allows Data Connect to distinguish between fields that haven't been set and fields that have been set to null. A field can be set by calling its respective setter method like below: -```dart -class SearchMovieVariablesBuilder { - ... - - SearchMovieVariablesBuilder titleInput(String? t) { - _titleInput.value = t; - return this; - } - SearchMovieVariablesBuilder genre(String? t) { - _genre.value = t; - return this; - } - - ... -} -ExampleConnector.instance.searchMovie() -.titleInput(titleInput) -.genre(genre) -.execute(); -``` - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.searchMovie(); -SearchMovieData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.searchMovie().ref(); -ref.execute(); - -ref.subscribe(...); -``` - -## Mutations - -### CreateMovie -#### Required Arguments -```dart -String title = ...; -String genre = ...; -String imageUrl = ...; -ExampleConnector.instance.createMovie( - title: title, - genre: genre, - imageUrl: imageUrl, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.createMovie( - title: title, - genre: genre, - imageUrl: imageUrl, -); -CreateMovieData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String title = ...; -String genre = ...; -String imageUrl = ...; - -final ref = ExampleConnector.instance.createMovie( - title: title, - genre: genre, - imageUrl: imageUrl, -).ref(); -ref.execute(); -``` - - -### UpsertUser -#### Required Arguments -```dart -String username = ...; -ExampleConnector.instance.upsertUser( - username: username, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.upsertUser( - username: username, -); -UpsertUserData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String username = ...; - -final ref = ExampleConnector.instance.upsertUser( - username: username, -).ref(); -ref.execute(); -``` - - -### AddReview -#### Required Arguments -```dart -String movieId = ...; -int rating = ...; -String reviewText = ...; -ExampleConnector.instance.addReview( - movieId: movieId, - rating: rating, - reviewText: reviewText, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.addReview( - movieId: movieId, - rating: rating, - reviewText: reviewText, -); -AddReviewData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String movieId = ...; -int rating = ...; -String reviewText = ...; - -final ref = ExampleConnector.instance.addReview( - movieId: movieId, - rating: rating, - reviewText: reviewText, -).ref(); -ref.execute(); -``` - - -### DeleteReview -#### Required Arguments -```dart -String movieId = ...; -ExampleConnector.instance.deleteReview( - movieId: movieId, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.deleteReview( - movieId: movieId, -); -DeleteReviewData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String movieId = ...; - -final ref = ExampleConnector.instance.deleteReview( - movieId: movieId, -).ref(); -ref.execute(); -``` - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/add_review.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/add_review.dart deleted file mode 100644 index fc78c415..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/add_review.dart +++ /dev/null @@ -1,139 +0,0 @@ -part of 'generated.dart'; - -class AddReviewVariablesBuilder { - String movieId; - int rating; - String reviewText; - - final FirebaseDataConnect _dataConnect; - AddReviewVariablesBuilder(this._dataConnect, {required this.movieId,required this.rating,required this.reviewText,}); - Deserializer dataDeserializer = (dynamic json) => AddReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (AddReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - AddReviewVariables vars= AddReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,); - return _dataConnect.mutation("AddReview", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class AddReviewReviewUpsert { - final String userId; - final String movieId; - AddReviewReviewUpsert.fromJson(dynamic json): - - userId = nativeFromJson(json['userId']), - movieId = nativeFromJson(json['movieId']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final AddReviewReviewUpsert otherTyped = other as AddReviewReviewUpsert; - return userId == otherTyped.userId && - movieId == otherTyped.movieId; - - } - @override - int get hashCode => Object.hashAll([userId.hashCode, movieId.hashCode]); - - - Map toJson() { - Map json = {}; - json['userId'] = nativeToJson(userId); - json['movieId'] = nativeToJson(movieId); - return json; - } - - AddReviewReviewUpsert({ - required this.userId, - required this.movieId, - }); -} - -@immutable -class AddReviewData { - final AddReviewReviewUpsert review_upsert; - AddReviewData.fromJson(dynamic json): - - review_upsert = AddReviewReviewUpsert.fromJson(json['review_upsert']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final AddReviewData otherTyped = other as AddReviewData; - return review_upsert == otherTyped.review_upsert; - - } - @override - int get hashCode => review_upsert.hashCode; - - - Map toJson() { - Map json = {}; - json['review_upsert'] = review_upsert.toJson(); - return json; - } - - AddReviewData({ - required this.review_upsert, - }); -} - -@immutable -class AddReviewVariables { - final String movieId; - final int rating; - final String reviewText; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - AddReviewVariables.fromJson(Map json): - - movieId = nativeFromJson(json['movieId']), - rating = nativeFromJson(json['rating']), - reviewText = nativeFromJson(json['reviewText']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final AddReviewVariables otherTyped = other as AddReviewVariables; - return movieId == otherTyped.movieId && - rating == otherTyped.rating && - reviewText == otherTyped.reviewText; - - } - @override - int get hashCode => Object.hashAll([movieId.hashCode, rating.hashCode, reviewText.hashCode]); - - - Map toJson() { - Map json = {}; - json['movieId'] = nativeToJson(movieId); - json['rating'] = nativeToJson(rating); - json['reviewText'] = nativeToJson(reviewText); - return json; - } - - AddReviewVariables({ - required this.movieId, - required this.rating, - required this.reviewText, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/create_movie.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/create_movie.dart deleted file mode 100644 index abdd637c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/create_movie.dart +++ /dev/null @@ -1,134 +0,0 @@ -part of 'generated.dart'; - -class CreateMovieVariablesBuilder { - String title; - String genre; - String imageUrl; - - final FirebaseDataConnect _dataConnect; - CreateMovieVariablesBuilder(this._dataConnect, {required this.title,required this.genre,required this.imageUrl,}); - Deserializer dataDeserializer = (dynamic json) => CreateMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (CreateMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - CreateMovieVariables vars= CreateMovieVariables(title: title,genre: genre,imageUrl: imageUrl,); - return _dataConnect.mutation("CreateMovie", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class CreateMovieMovieInsert { - final String id; - CreateMovieMovieInsert.fromJson(dynamic json): - - id = nativeFromJson(json['id']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final CreateMovieMovieInsert otherTyped = other as CreateMovieMovieInsert; - return id == otherTyped.id; - - } - @override - int get hashCode => id.hashCode; - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - return json; - } - - CreateMovieMovieInsert({ - required this.id, - }); -} - -@immutable -class CreateMovieData { - final CreateMovieMovieInsert movie_insert; - CreateMovieData.fromJson(dynamic json): - - movie_insert = CreateMovieMovieInsert.fromJson(json['movie_insert']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final CreateMovieData otherTyped = other as CreateMovieData; - return movie_insert == otherTyped.movie_insert; - - } - @override - int get hashCode => movie_insert.hashCode; - - - Map toJson() { - Map json = {}; - json['movie_insert'] = movie_insert.toJson(); - return json; - } - - CreateMovieData({ - required this.movie_insert, - }); -} - -@immutable -class CreateMovieVariables { - final String title; - final String genre; - final String imageUrl; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - CreateMovieVariables.fromJson(Map json): - - title = nativeFromJson(json['title']), - genre = nativeFromJson(json['genre']), - imageUrl = nativeFromJson(json['imageUrl']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final CreateMovieVariables otherTyped = other as CreateMovieVariables; - return title == otherTyped.title && - genre == otherTyped.genre && - imageUrl == otherTyped.imageUrl; - - } - @override - int get hashCode => Object.hashAll([title.hashCode, genre.hashCode, imageUrl.hashCode]); - - - Map toJson() { - Map json = {}; - json['title'] = nativeToJson(title); - json['genre'] = nativeToJson(genre); - json['imageUrl'] = nativeToJson(imageUrl); - return json; - } - - CreateMovieVariables({ - required this.title, - required this.genre, - required this.imageUrl, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/delete_review.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/delete_review.dart deleted file mode 100644 index e62dd741..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/delete_review.dart +++ /dev/null @@ -1,129 +0,0 @@ -part of 'generated.dart'; - -class DeleteReviewVariablesBuilder { - String movieId; - - final FirebaseDataConnect _dataConnect; - DeleteReviewVariablesBuilder(this._dataConnect, {required this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => DeleteReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (DeleteReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - DeleteReviewVariables vars= DeleteReviewVariables(movieId: movieId,); - return _dataConnect.mutation("DeleteReview", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class DeleteReviewReviewDelete { - final String userId; - final String movieId; - DeleteReviewReviewDelete.fromJson(dynamic json): - - userId = nativeFromJson(json['userId']), - movieId = nativeFromJson(json['movieId']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final DeleteReviewReviewDelete otherTyped = other as DeleteReviewReviewDelete; - return userId == otherTyped.userId && - movieId == otherTyped.movieId; - - } - @override - int get hashCode => Object.hashAll([userId.hashCode, movieId.hashCode]); - - - Map toJson() { - Map json = {}; - json['userId'] = nativeToJson(userId); - json['movieId'] = nativeToJson(movieId); - return json; - } - - DeleteReviewReviewDelete({ - required this.userId, - required this.movieId, - }); -} - -@immutable -class DeleteReviewData { - final DeleteReviewReviewDelete? review_delete; - DeleteReviewData.fromJson(dynamic json): - - review_delete = json['review_delete'] == null ? null : DeleteReviewReviewDelete.fromJson(json['review_delete']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final DeleteReviewData otherTyped = other as DeleteReviewData; - return review_delete == otherTyped.review_delete; - - } - @override - int get hashCode => review_delete.hashCode; - - - Map toJson() { - Map json = {}; - if (review_delete != null) { - json['review_delete'] = review_delete!.toJson(); - } - return json; - } - - DeleteReviewData({ - this.review_delete, - }); -} - -@immutable -class DeleteReviewVariables { - final String movieId; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - DeleteReviewVariables.fromJson(Map json): - - movieId = nativeFromJson(json['movieId']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final DeleteReviewVariables otherTyped = other as DeleteReviewVariables; - return movieId == otherTyped.movieId; - - } - @override - int get hashCode => movieId.hashCode; - - - Map toJson() { - Map json = {}; - json['movieId'] = nativeToJson(movieId); - return json; - } - - DeleteReviewVariables({ - required this.movieId, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/generated.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/generated.dart deleted file mode 100644 index 580adbb3..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/generated.dart +++ /dev/null @@ -1,93 +0,0 @@ -library dataconnect_generated; -import 'package:firebase_data_connect/firebase_data_connect.dart'; -import 'package:flutter/foundation.dart'; -import 'dart:convert'; - -part 'create_movie.dart'; - -part 'upsert_user.dart'; - -part 'add_review.dart'; - -part 'delete_review.dart'; - -part 'list_movies.dart'; - -part 'list_users.dart'; - -part 'list_user_reviews.dart'; - -part 'get_movie_by_id.dart'; - -part 'search_movie.dart'; - - - - - - - -class ExampleConnector { - - - CreateMovieVariablesBuilder createMovie ({required String title, required String genre, required String imageUrl, }) { - return CreateMovieVariablesBuilder(dataConnect, title: title,genre: genre,imageUrl: imageUrl,); - } - - - UpsertUserVariablesBuilder upsertUser ({required String username, }) { - return UpsertUserVariablesBuilder(dataConnect, username: username,); - } - - - AddReviewVariablesBuilder addReview ({required String movieId, required int rating, required String reviewText, }) { - return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); - } - - - DeleteReviewVariablesBuilder deleteReview ({required String movieId, }) { - return DeleteReviewVariablesBuilder(dataConnect, movieId: movieId,); - } - - - ListMoviesVariablesBuilder listMovies () { - return ListMoviesVariablesBuilder(dataConnect, ); - } - - - ListUsersVariablesBuilder listUsers () { - return ListUsersVariablesBuilder(dataConnect, ); - } - - - ListUserReviewsVariablesBuilder listUserReviews () { - return ListUserReviewsVariablesBuilder(dataConnect, ); - } - - - GetMovieByIdVariablesBuilder getMovieById ({required String id, }) { - return GetMovieByIdVariablesBuilder(dataConnect, id: id,); - } - - - SearchMovieVariablesBuilder searchMovie () { - return SearchMovieVariablesBuilder(dataConnect, ); - } - - - static ConnectorConfig connectorConfig = ConnectorConfig( - 'us-central1', - 'example', - 'client-krow-poc', - ); - - ExampleConnector({required this.dataConnect}); - static ExampleConnector get instance { - return ExampleConnector( - dataConnect: FirebaseDataConnect.instanceFor( - connectorConfig: connectorConfig, - sdkType: CallerSDKType.generated)); - } - - FirebaseDataConnect dataConnect; -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/get_movie_by_id.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/get_movie_by_id.dart deleted file mode 100644 index 154704ac..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/get_movie_by_id.dart +++ /dev/null @@ -1,297 +0,0 @@ -part of 'generated.dart'; - -class GetMovieByIdVariablesBuilder { - String id; - - final FirebaseDataConnect _dataConnect; - GetMovieByIdVariablesBuilder(this._dataConnect, {required this.id,}); - Deserializer dataDeserializer = (dynamic json) => GetMovieByIdData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (GetMovieByIdVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - GetMovieByIdVariables vars= GetMovieByIdVariables(id: id,); - return _dataConnect.query("GetMovieById", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class GetMovieByIdMovie { - final String id; - final String title; - final String imageUrl; - final String? genre; - final GetMovieByIdMovieMetadata? metadata; - final List reviews; - GetMovieByIdMovie.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']), - imageUrl = nativeFromJson(json['imageUrl']), - genre = json['genre'] == null ? null : nativeFromJson(json['genre']), - metadata = json['metadata'] == null ? null : GetMovieByIdMovieMetadata.fromJson(json['metadata']), - reviews = (json['reviews'] as List) - .map((e) => GetMovieByIdMovieReviews.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovie otherTyped = other as GetMovieByIdMovie; - return id == otherTyped.id && - title == otherTyped.title && - imageUrl == otherTyped.imageUrl && - genre == otherTyped.genre && - metadata == otherTyped.metadata && - reviews == otherTyped.reviews; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode, imageUrl.hashCode, genre.hashCode, metadata.hashCode, reviews.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - json['imageUrl'] = nativeToJson(imageUrl); - if (genre != null) { - json['genre'] = nativeToJson(genre); - } - if (metadata != null) { - json['metadata'] = metadata!.toJson(); - } - json['reviews'] = reviews.map((e) => e.toJson()).toList(); - return json; - } - - GetMovieByIdMovie({ - required this.id, - required this.title, - required this.imageUrl, - this.genre, - this.metadata, - required this.reviews, - }); -} - -@immutable -class GetMovieByIdMovieMetadata { - final double? rating; - final int? releaseYear; - final String? description; - GetMovieByIdMovieMetadata.fromJson(dynamic json): - - rating = json['rating'] == null ? null : nativeFromJson(json['rating']), - releaseYear = json['releaseYear'] == null ? null : nativeFromJson(json['releaseYear']), - description = json['description'] == null ? null : nativeFromJson(json['description']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovieMetadata otherTyped = other as GetMovieByIdMovieMetadata; - return rating == otherTyped.rating && - releaseYear == otherTyped.releaseYear && - description == otherTyped.description; - - } - @override - int get hashCode => Object.hashAll([rating.hashCode, releaseYear.hashCode, description.hashCode]); - - - Map toJson() { - Map json = {}; - if (rating != null) { - json['rating'] = nativeToJson(rating); - } - if (releaseYear != null) { - json['releaseYear'] = nativeToJson(releaseYear); - } - if (description != null) { - json['description'] = nativeToJson(description); - } - return json; - } - - GetMovieByIdMovieMetadata({ - this.rating, - this.releaseYear, - this.description, - }); -} - -@immutable -class GetMovieByIdMovieReviews { - final String? reviewText; - final DateTime reviewDate; - final int? rating; - final GetMovieByIdMovieReviewsUser user; - GetMovieByIdMovieReviews.fromJson(dynamic json): - - reviewText = json['reviewText'] == null ? null : nativeFromJson(json['reviewText']), - reviewDate = nativeFromJson(json['reviewDate']), - rating = json['rating'] == null ? null : nativeFromJson(json['rating']), - user = GetMovieByIdMovieReviewsUser.fromJson(json['user']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovieReviews otherTyped = other as GetMovieByIdMovieReviews; - return reviewText == otherTyped.reviewText && - reviewDate == otherTyped.reviewDate && - rating == otherTyped.rating && - user == otherTyped.user; - - } - @override - int get hashCode => Object.hashAll([reviewText.hashCode, reviewDate.hashCode, rating.hashCode, user.hashCode]); - - - Map toJson() { - Map json = {}; - if (reviewText != null) { - json['reviewText'] = nativeToJson(reviewText); - } - json['reviewDate'] = nativeToJson(reviewDate); - if (rating != null) { - json['rating'] = nativeToJson(rating); - } - json['user'] = user.toJson(); - return json; - } - - GetMovieByIdMovieReviews({ - this.reviewText, - required this.reviewDate, - this.rating, - required this.user, - }); -} - -@immutable -class GetMovieByIdMovieReviewsUser { - final String id; - final String username; - GetMovieByIdMovieReviewsUser.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - username = nativeFromJson(json['username']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovieReviewsUser otherTyped = other as GetMovieByIdMovieReviewsUser; - return id == otherTyped.id && - username == otherTyped.username; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, username.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['username'] = nativeToJson(username); - return json; - } - - GetMovieByIdMovieReviewsUser({ - required this.id, - required this.username, - }); -} - -@immutable -class GetMovieByIdData { - final GetMovieByIdMovie? movie; - GetMovieByIdData.fromJson(dynamic json): - - movie = json['movie'] == null ? null : GetMovieByIdMovie.fromJson(json['movie']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdData otherTyped = other as GetMovieByIdData; - return movie == otherTyped.movie; - - } - @override - int get hashCode => movie.hashCode; - - - Map toJson() { - Map json = {}; - if (movie != null) { - json['movie'] = movie!.toJson(); - } - return json; - } - - GetMovieByIdData({ - this.movie, - }); -} - -@immutable -class GetMovieByIdVariables { - final String id; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - GetMovieByIdVariables.fromJson(Map json): - - id = nativeFromJson(json['id']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdVariables otherTyped = other as GetMovieByIdVariables; - return id == otherTyped.id; - - } - @override - int get hashCode => id.hashCode; - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - return json; - } - - GetMovieByIdVariables({ - required this.id, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_movies.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_movies.dart deleted file mode 100644 index 4a67d768..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_movies.dart +++ /dev/null @@ -1,105 +0,0 @@ -part of 'generated.dart'; - -class ListMoviesVariablesBuilder { - - final FirebaseDataConnect _dataConnect; - ListMoviesVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); - - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - - return _dataConnect.query("ListMovies", dataDeserializer, emptySerializer, null); - } -} - -@immutable -class ListMoviesMovies { - final String id; - final String title; - final String imageUrl; - final String? genre; - ListMoviesMovies.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']), - imageUrl = nativeFromJson(json['imageUrl']), - genre = json['genre'] == null ? null : nativeFromJson(json['genre']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListMoviesMovies otherTyped = other as ListMoviesMovies; - return id == otherTyped.id && - title == otherTyped.title && - imageUrl == otherTyped.imageUrl && - genre == otherTyped.genre; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode, imageUrl.hashCode, genre.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - json['imageUrl'] = nativeToJson(imageUrl); - if (genre != null) { - json['genre'] = nativeToJson(genre); - } - return json; - } - - ListMoviesMovies({ - required this.id, - required this.title, - required this.imageUrl, - this.genre, - }); -} - -@immutable -class ListMoviesData { - final List movies; - ListMoviesData.fromJson(dynamic json): - - movies = (json['movies'] as List) - .map((e) => ListMoviesMovies.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListMoviesData otherTyped = other as ListMoviesData; - return movies == otherTyped.movies; - - } - @override - int get hashCode => movies.hashCode; - - - Map toJson() { - Map json = {}; - json['movies'] = movies.map((e) => e.toJson()).toList(); - return json; - } - - ListMoviesData({ - required this.movies, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_user_reviews.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_user_reviews.dart deleted file mode 100644 index d6053f58..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_user_reviews.dart +++ /dev/null @@ -1,192 +0,0 @@ -part of 'generated.dart'; - -class ListUserReviewsVariablesBuilder { - - final FirebaseDataConnect _dataConnect; - ListUserReviewsVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListUserReviewsData.fromJson(jsonDecode(json)); - - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - - return _dataConnect.query("ListUserReviews", dataDeserializer, emptySerializer, null); - } -} - -@immutable -class ListUserReviewsUser { - final String id; - final String username; - final List reviews; - ListUserReviewsUser.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - username = nativeFromJson(json['username']), - reviews = (json['reviews'] as List) - .map((e) => ListUserReviewsUserReviews.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsUser otherTyped = other as ListUserReviewsUser; - return id == otherTyped.id && - username == otherTyped.username && - reviews == otherTyped.reviews; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, username.hashCode, reviews.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['username'] = nativeToJson(username); - json['reviews'] = reviews.map((e) => e.toJson()).toList(); - return json; - } - - ListUserReviewsUser({ - required this.id, - required this.username, - required this.reviews, - }); -} - -@immutable -class ListUserReviewsUserReviews { - final int? rating; - final DateTime reviewDate; - final String? reviewText; - final ListUserReviewsUserReviewsMovie movie; - ListUserReviewsUserReviews.fromJson(dynamic json): - - rating = json['rating'] == null ? null : nativeFromJson(json['rating']), - reviewDate = nativeFromJson(json['reviewDate']), - reviewText = json['reviewText'] == null ? null : nativeFromJson(json['reviewText']), - movie = ListUserReviewsUserReviewsMovie.fromJson(json['movie']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsUserReviews otherTyped = other as ListUserReviewsUserReviews; - return rating == otherTyped.rating && - reviewDate == otherTyped.reviewDate && - reviewText == otherTyped.reviewText && - movie == otherTyped.movie; - - } - @override - int get hashCode => Object.hashAll([rating.hashCode, reviewDate.hashCode, reviewText.hashCode, movie.hashCode]); - - - Map toJson() { - Map json = {}; - if (rating != null) { - json['rating'] = nativeToJson(rating); - } - json['reviewDate'] = nativeToJson(reviewDate); - if (reviewText != null) { - json['reviewText'] = nativeToJson(reviewText); - } - json['movie'] = movie.toJson(); - return json; - } - - ListUserReviewsUserReviews({ - this.rating, - required this.reviewDate, - this.reviewText, - required this.movie, - }); -} - -@immutable -class ListUserReviewsUserReviewsMovie { - final String id; - final String title; - ListUserReviewsUserReviewsMovie.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsUserReviewsMovie otherTyped = other as ListUserReviewsUserReviewsMovie; - return id == otherTyped.id && - title == otherTyped.title; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - return json; - } - - ListUserReviewsUserReviewsMovie({ - required this.id, - required this.title, - }); -} - -@immutable -class ListUserReviewsData { - final ListUserReviewsUser? user; - ListUserReviewsData.fromJson(dynamic json): - - user = json['user'] == null ? null : ListUserReviewsUser.fromJson(json['user']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsData otherTyped = other as ListUserReviewsData; - return user == otherTyped.user; - - } - @override - int get hashCode => user.hashCode; - - - Map toJson() { - Map json = {}; - if (user != null) { - json['user'] = user!.toJson(); - } - return json; - } - - ListUserReviewsData({ - this.user, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_users.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_users.dart deleted file mode 100644 index 5fead7eb..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/list_users.dart +++ /dev/null @@ -1,93 +0,0 @@ -part of 'generated.dart'; - -class ListUsersVariablesBuilder { - - final FirebaseDataConnect _dataConnect; - ListUsersVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListUsersData.fromJson(jsonDecode(json)); - - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - - return _dataConnect.query("ListUsers", dataDeserializer, emptySerializer, null); - } -} - -@immutable -class ListUsersUsers { - final String id; - final String username; - ListUsersUsers.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - username = nativeFromJson(json['username']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUsersUsers otherTyped = other as ListUsersUsers; - return id == otherTyped.id && - username == otherTyped.username; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, username.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['username'] = nativeToJson(username); - return json; - } - - ListUsersUsers({ - required this.id, - required this.username, - }); -} - -@immutable -class ListUsersData { - final List users; - ListUsersData.fromJson(dynamic json): - - users = (json['users'] as List) - .map((e) => ListUsersUsers.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUsersData otherTyped = other as ListUsersData; - return users == otherTyped.users; - - } - @override - int get hashCode => users.hashCode; - - - Map toJson() { - Map json = {}; - json['users'] = users.map((e) => e.toJson()).toList(); - return json; - } - - ListUsersData({ - required this.users, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/search_movie.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/search_movie.dart deleted file mode 100644 index 19e5f2d7..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/search_movie.dart +++ /dev/null @@ -1,167 +0,0 @@ -part of 'generated.dart'; - -class SearchMovieVariablesBuilder { - Optional _titleInput = Optional.optional(nativeFromJson, nativeToJson); - Optional _genre = Optional.optional(nativeFromJson, nativeToJson); - - final FirebaseDataConnect _dataConnect; - SearchMovieVariablesBuilder titleInput(String? t) { - _titleInput.value = t; - return this; - } - SearchMovieVariablesBuilder genre(String? t) { - _genre.value = t; - return this; - } - - SearchMovieVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => SearchMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (SearchMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - SearchMovieVariables vars= SearchMovieVariables(titleInput: _titleInput,genre: _genre,); - return _dataConnect.query("SearchMovie", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class SearchMovieMovies { - final String id; - final String title; - final String? genre; - final String imageUrl; - SearchMovieMovies.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']), - genre = json['genre'] == null ? null : nativeFromJson(json['genre']), - imageUrl = nativeFromJson(json['imageUrl']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final SearchMovieMovies otherTyped = other as SearchMovieMovies; - return id == otherTyped.id && - title == otherTyped.title && - genre == otherTyped.genre && - imageUrl == otherTyped.imageUrl; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode, genre.hashCode, imageUrl.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - if (genre != null) { - json['genre'] = nativeToJson(genre); - } - json['imageUrl'] = nativeToJson(imageUrl); - return json; - } - - SearchMovieMovies({ - required this.id, - required this.title, - this.genre, - required this.imageUrl, - }); -} - -@immutable -class SearchMovieData { - final List movies; - SearchMovieData.fromJson(dynamic json): - - movies = (json['movies'] as List) - .map((e) => SearchMovieMovies.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final SearchMovieData otherTyped = other as SearchMovieData; - return movies == otherTyped.movies; - - } - @override - int get hashCode => movies.hashCode; - - - Map toJson() { - Map json = {}; - json['movies'] = movies.map((e) => e.toJson()).toList(); - return json; - } - - SearchMovieData({ - required this.movies, - }); -} - -@immutable -class SearchMovieVariables { - late final OptionaltitleInput; - late final Optionalgenre; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - SearchMovieVariables.fromJson(Map json) { - - - titleInput = Optional.optional(nativeFromJson, nativeToJson); - titleInput.value = json['titleInput'] == null ? null : nativeFromJson(json['titleInput']); - - - genre = Optional.optional(nativeFromJson, nativeToJson); - genre.value = json['genre'] == null ? null : nativeFromJson(json['genre']); - - } - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final SearchMovieVariables otherTyped = other as SearchMovieVariables; - return titleInput == otherTyped.titleInput && - genre == otherTyped.genre; - - } - @override - int get hashCode => Object.hashAll([titleInput.hashCode, genre.hashCode]); - - - Map toJson() { - Map json = {}; - if(titleInput.state == OptionalState.set) { - json['titleInput'] = titleInput.toJson(); - } - if(genre.state == OptionalState.set) { - json['genre'] = genre.toJson(); - } - return json; - } - - SearchMovieVariables({ - required this.titleInput, - required this.genre, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/upsert_user.dart b/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/upsert_user.dart deleted file mode 100644 index f797b726..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/dataconnect_generated/upsert_user.dart +++ /dev/null @@ -1,122 +0,0 @@ -part of 'generated.dart'; - -class UpsertUserVariablesBuilder { - String username; - - final FirebaseDataConnect _dataConnect; - UpsertUserVariablesBuilder(this._dataConnect, {required this.username,}); - Deserializer dataDeserializer = (dynamic json) => UpsertUserData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (UpsertUserVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - UpsertUserVariables vars= UpsertUserVariables(username: username,); - return _dataConnect.mutation("UpsertUser", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class UpsertUserUserUpsert { - final String id; - UpsertUserUserUpsert.fromJson(dynamic json): - - id = nativeFromJson(json['id']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final UpsertUserUserUpsert otherTyped = other as UpsertUserUserUpsert; - return id == otherTyped.id; - - } - @override - int get hashCode => id.hashCode; - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - return json; - } - - UpsertUserUserUpsert({ - required this.id, - }); -} - -@immutable -class UpsertUserData { - final UpsertUserUserUpsert user_upsert; - UpsertUserData.fromJson(dynamic json): - - user_upsert = UpsertUserUserUpsert.fromJson(json['user_upsert']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final UpsertUserData otherTyped = other as UpsertUserData; - return user_upsert == otherTyped.user_upsert; - - } - @override - int get hashCode => user_upsert.hashCode; - - - Map toJson() { - Map json = {}; - json['user_upsert'] = user_upsert.toJson(); - return json; - } - - UpsertUserData({ - required this.user_upsert, - }); -} - -@immutable -class UpsertUserVariables { - final String username; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - UpsertUserVariables.fromJson(Map json): - - username = nativeFromJson(json['username']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final UpsertUserVariables otherTyped = other as UpsertUserVariables; - return username == otherTyped.username; - - } - @override - int get hashCode => username.hashCode; - - - Map toJson() { - Map json = {}; - json['username'] = nativeToJson(username); - return json; - } - - UpsertUserVariables({ - required this.username, - }); -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/main.dart b/apps/mobile/prototypes/client_mobile_application/lib/main.dart deleted file mode 100644 index 336a9677..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/main.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; -import 'theme.dart'; -import 'router.dart'; -import 'widgets/web_mobile_frame.dart'; - -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - - const app = AppRoot(); - - runApp(ProviderScope(child: kIsWeb ? const WebMobileFrame(child: app) : app)); -} - -class AppRoot extends ConsumerWidget { - const AppRoot({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return MaterialApp.router( - title: 'Krow Client App', - theme: AppTheme.lightTheme, - routerConfig: router, - debugShowCheckedModeBanner: false, - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/router.dart b/apps/mobile/prototypes/client_mobile_application/lib/router.dart deleted file mode 100644 index 47109000..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/router.dart +++ /dev/null @@ -1,165 +0,0 @@ -import 'package:go_router/go_router.dart'; -import 'screens/auth/client_get_started_screen.dart'; -import 'screens/auth/client_sign_in_screen.dart'; -import 'screens/auth/client_sign_up_screen.dart'; -import 'screens/client/client_home_screen.dart'; -import 'screens/client/client_workers_screen.dart'; -import 'screens/client/client_timesheets_screen.dart'; -import 'screens/client/client_shifts_screen.dart'; -import 'screens/client/client_reports_screen.dart'; -import 'screens/client/create_order_screen.dart'; -import 'screens/client/client_settings_screen.dart'; -import 'screens/client/client_billing_screen.dart'; -import 'screens/client/client_coverage_screen.dart'; -import 'screens/client/client_hubs_screen.dart'; -import 'screens/client/verify_worker_attire_screen.dart'; -import 'screens/client/reports/daily_ops_report_screen.dart'; -import 'screens/client/reports/spend_report_screen.dart'; -import 'screens/client/reports/forecast_report_screen.dart'; -import 'screens/client/reports/performance_report_screen.dart'; -import 'screens/client/reports/no_show_report_screen.dart'; -import 'screens/client/reports/coverage_report_screen.dart'; -import 'screens/client/create_order_pages/rapid_order_flow_page.dart'; -import 'screens/client/create_order_pages/one_time_order_flow_page.dart'; -import 'screens/client/create_order_pages/recurring_order_flow_page.dart'; -import 'screens/client/create_order_pages/permanent_order_flow_page.dart'; -import 'widgets/scaffold_with_nav_bar.dart'; - -final router = GoRouter( - initialLocation: '/client-get-started', - routes: [ - GoRoute( - path: '/client-get-started', - builder: (context, state) => const ClientGetStartedScreen(), - ), - GoRoute( - path: '/client-sign-in', - builder: (context, state) => const ClientSignInScreen(), - ), - GoRoute( - path: '/client-sign-up', - builder: (context, state) => const ClientSignUpScreen(), - ), - GoRoute( - path: '/create-order', - builder: (context, state) => const CreateOrderScreen(), - routes: [ - GoRoute( - path: 'rapid', - builder: (context, state) => const RapidOrderFlowPage(), - ), - GoRoute( - path: 'one-time', - builder: (context, state) => const OneTimeOrderFlowPage(), - ), - GoRoute( - path: 'recurring', - builder: (context, state) => const RecurringOrderFlowPage(), - ), - GoRoute( - path: 'permanent', - builder: (context, state) => const PermanentOrderFlowPage(), - ), - ], - ), - GoRoute( - path: '/client-settings', - builder: (context, state) => const ClientSettingsScreen(), - ), - GoRoute( - path: '/client-hubs', - builder: (context, state) => const ClientHubsScreen(), - ), - GoRoute( - path: '/verify-worker-attire', - builder: (context, state) => const VerifyWorkerAttireScreen(), - ), - // Report Routes - GoRoute( - path: '/daily-ops-report', - builder: (context, state) => const DailyOpsReportScreen(), - ), - GoRoute( - path: '/spend-report', - builder: (context, state) => const SpendReportScreen(), - ), - GoRoute( - path: '/forecast-report', - builder: (context, state) => const ForecastReportScreen(), - ), - GoRoute( - path: '/performance-report', - builder: (context, state) => const PerformanceReportScreen(), - ), - GoRoute( - path: '/no-show-report', - builder: (context, state) => const NoShowReportScreen(), - ), - GoRoute( - path: '/coverage-report-detail', - builder: (context, state) => const CoverageReportScreen(), - ), - // Moved Workers and Timesheets out of bottom nav, accessible as standalone routes - GoRoute( - path: '/client-workers', - builder: (context, state) => const ClientWorkersScreen(), - ), - GoRoute( - path: '/client-timesheets', - builder: (context, state) => const ClientTimesheetsScreen(), - ), - - StatefulShellRoute.indexedStack( - builder: (context, state, navigationShell) { - return ScaffoldWithNavBar(navigationShell: navigationShell); - }, - branches: [ - // Index 0: Coverage - StatefulShellBranch( - routes: [ - GoRoute( - path: '/client-coverage', - builder: (context, state) => const ClientCoverageScreen(), - ), - ], - ), - // Index 1: Billing - StatefulShellBranch( - routes: [ - GoRoute( - path: '/client-billing', - builder: (context, state) => const ClientBillingScreen(), - ), - ], - ), - // Index 2: Home - StatefulShellBranch( - routes: [ - GoRoute( - path: '/client-home', - builder: (context, state) => const ClientHomeScreen(), - ), - ], - ), - // Index 3: Orders (Shifts) - StatefulShellBranch( - routes: [ - GoRoute( - path: '/client-shifts', - builder: (context, state) => const ClientShiftsScreen(), - ), - ], - ), - // Index 4: Reports - StatefulShellBranch( - routes: [ - GoRoute( - path: '/client-reports', - builder: (context, state) => const ClientReportsScreen(), - ), - ], - ), - ], - ), - ], -); diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_get_started_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_get_started_screen.dart deleted file mode 100644 index 77f20b1e..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_get_started_screen.dart +++ /dev/null @@ -1,392 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class ClientGetStartedScreen extends StatelessWidget { - const ClientGetStartedScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBlue, - body: SafeArea( - child: Column( - children: [ - const SizedBox(height: 12), - // Logo - Image.network( - 'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png', - height: 40, - fit: BoxFit.contain, - ), - - // Floating Cards Area - const Expanded( - child: Stack( - alignment: Alignment.center, - clipBehavior: Clip.none, - children: [ - // Card 1 - Shift Order - Positioned(left: 24, top: 32, child: _ShiftOrderCard()), - - // Card 2 - Worker Profile - Positioned(right: 24, top: 16, child: _WorkerProfileCard()), - - // Card 3 - Calendar - Positioned(top: 112, child: _CalendarCard()), - ], - ), - ), - - // Bottom Content - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 40), - child: Column( - children: [ - const Text( - 'Take Control of Your\nShifts and Events', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white, - fontSize: 30, - fontWeight: FontWeight.bold, - height: 1.1, - ), - ), - const SizedBox(height: 12), - const Text( - 'Streamline your operations with powerful tools to manage schedules, track performance, and keep your team on the same page—all in one place', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.white70, - fontSize: 14, - height: 1.4, - ), - ), - const SizedBox(height: 32), - - // Sign In Button - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () => context.push('/client-sign-in'), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowYellow, - foregroundColor: AppColors.krowCharcoal, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - elevation: 0, - ), - child: const Text( - 'Sign In', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ), - ), - - const SizedBox(height: 12), - - // Create Account Button - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () => context.push('/client-sign-up'), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: AppColors.krowCharcoal, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - elevation: 0, - ), - child: const Text( - 'Create Account', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ), - ), - ], - ), - ), - ], - ), - ), - ); - } -} - -class _ShiftOrderCard extends StatelessWidget { - const _ShiftOrderCard(); - - @override - Widget build(BuildContext context) { - return Transform.rotate( - angle: -12 * 3.14159 / 180, - child: Container( - width: 160, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - children: [ - Container( - width: 20, - height: 20, - decoration: BoxDecoration( - color: Colors.green.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: const Center( - child: Icon(Icons.check, size: 14, color: Colors.green), - ), - ), - const SizedBox(width: 8), - const Text( - 'Confirmed', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Colors.green, - ), - ), - ], - ), - const SizedBox(height: 8), - const Text( - 'Taste of the Town', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'Event Catering', - style: TextStyle(fontSize: 10, color: Colors.grey), - ), - const SizedBox(height: 8), - const Row( - children: [ - Icon(LucideIcons.calendar, size: 12, color: Colors.grey), - SizedBox(width: 4), - Text( - '01.21.2025, 06:30 pm', - style: TextStyle(fontSize: 10, color: Colors.grey), - ), - ], - ), - ], - ), - ), - ); - } -} - -class _WorkerProfileCard extends StatelessWidget { - const _WorkerProfileCard(); - - @override - Widget build(BuildContext context) { - return Transform.rotate( - angle: 8 * 3.14159 / 180, - child: Container( - width: 144, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 48, - height: 48, - decoration: const BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Colors.orangeAccent, Colors.deepOrange], - ), - ), - ), - const SizedBox(height: 8), - const Text( - '★ Verified', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Colors.green, - ), - ), - const SizedBox(height: 2), - const Text( - 'Jane Johnson', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'Server • 4.9 ★', - style: TextStyle(fontSize: 10, color: Colors.grey), - ), - ], - ), - ), - ); - } -} - -class _CalendarCard extends StatelessWidget { - const _CalendarCard(); - - @override - Widget build(BuildContext context) { - return Container( - width: 192, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'January 2025', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Icon(LucideIcons.clipboardList, size: 16, color: Colors.grey), - ], - ), - const SizedBox(height: 8), - GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 7, - mainAxisSpacing: 2, - crossAxisSpacing: 2, - childAspectRatio: 1, - ), - itemCount: 7 + 31, - itemBuilder: (context, index) { - if (index < 7) { - final days = ['S', 'M', 'T', 'W', 'T', 'F', 'S']; - return Center( - child: Text( - days[index], - style: const TextStyle(fontSize: 8, color: Colors.grey), - ), - ); - } - final day = index - 7 + 1; - Color? bg; - Color? text; - - if (day == 21) { - bg = Colors.blue.shade600; - text = Colors.white; - } else if (day == 15) { - // Adjusted to match visual roughly - bg = Colors.green.shade100; - text = Colors.green.shade600; - } - - return Container( - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(4), - ), - child: Center( - child: Text( - '$day', - style: TextStyle( - fontSize: 8, - color: text ?? Colors.grey.shade600, - ), - ), - ), - ); - }, - ), - const SizedBox(height: 8), - Row( - children: [ - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.green.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'Active Event', - style: TextStyle(fontSize: 8, color: Colors.green), - ), - ), - const SizedBox(width: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: Colors.amber.shade100, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'Assigned Event', - style: TextStyle(fontSize: 8, color: Colors.amber), - ), - ), - ], - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_sign_in_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_sign_in_screen.dart deleted file mode 100644 index f0a287be..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_sign_in_screen.dart +++ /dev/null @@ -1,384 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; - -class ClientSignInScreen extends StatefulWidget { - const ClientSignInScreen({super.key}); - - @override - State createState() => _ClientSignInScreenState(); -} - -class _ClientSignInScreenState extends State { - final _emailController = TextEditingController(); - final _passwordController = TextEditingController(); - bool _obscurePassword = true; - bool _isLoading = false; - - void _handleSignIn() async { - setState(() => _isLoading = true); - // Simulate sign in - await Future.delayed(const Duration(seconds: 1)); - if (mounted) { - setState(() => _isLoading = false); - context.go('/client-home'); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBlue, - body: SafeArea( - bottom: false, - child: Column( - children: [ - // Header - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - ), - ), - ), - ], - ), - ), - - Padding( - padding: const EdgeInsets.only(bottom: 32), - child: Image.network( - 'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png', - height: 40, - fit: BoxFit.contain, - ), - ), - - // Form Card - Expanded( - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - ), - padding: const EdgeInsets.fromLTRB(24, 32, 24, 0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Welcome Back', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - 'Sign in to manage your shifts and workers', - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 32), - - // Email Field - const Text( - 'Email', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _emailController, - decoration: InputDecoration( - hintText: 'Enter your email', - prefixIcon: const Icon( - LucideIcons.mail, - color: AppColors.krowMuted, - size: 20, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - const SizedBox(height: 20), - - // Password Field - const Text( - 'Password', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _passwordController, - obscureText: _obscurePassword, - decoration: InputDecoration( - hintText: 'Enter your password', - prefixIcon: const Icon( - LucideIcons.lock, - color: AppColors.krowMuted, - size: 20, - ), - suffixIcon: IconButton( - icon: Icon( - _obscurePassword - ? LucideIcons.eyeOff - : LucideIcons.eye, - color: AppColors.krowMuted, - size: 20, - ), - onPressed: () => setState( - () => _obscurePassword = !_obscurePassword, - ), - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - - // Forgot Password - Align( - alignment: Alignment.centerRight, - child: TextButton( - onPressed: () {}, - child: const Text( - 'Forgot Password?', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - ), - ), - - const SizedBox(height: 8), - - // Sign In Button - SizedBox( - height: 56, - child: ElevatedButton( - onPressed: _isLoading ? null : _handleSignIn, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: _isLoading - ? const CircularProgressIndicator( - color: Colors.white, - ) - : const Text( - 'Sign In', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - ), - ), - ), - - const SizedBox(height: 24), - - // Divider - const Row( - children: [ - Expanded(child: Divider(color: AppColors.krowBorder)), - Padding( - padding: EdgeInsets.symmetric(horizontal: 16), - child: Text( - 'or', - style: TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - ), - Expanded(child: Divider(color: AppColors.krowBorder)), - ], - ), - - const SizedBox(height: 24), - - // Social Buttons - _SocialButton( - text: 'Sign In with Apple', - icon: Icons.apple, - onPressed: _handleSignIn, - ), - const SizedBox(height: 12), - _SocialButton( - text: 'Sign In with Google', - icon: Icons - .flutter_dash, // Custom Google icon logic if needed - isGoogle: true, - onPressed: _handleSignIn, - ), - - const SizedBox(height: 32), - - // Sign Up Link - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - "Don't have an account? ", - style: TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - GestureDetector( - onTap: () => context.push('/client-sign-up'), - child: const Text( - 'Sign Up', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.w600, - fontSize: 14, - ), - ), - ), - ], - ), - const SizedBox(height: 40), - ], - ), - ), - ), - ), - ], - ), - ), - ); - } -} - -class _SocialButton extends StatelessWidget { - final String text; - final IconData? icon; - final bool isGoogle; - final VoidCallback onPressed; - - const _SocialButton({ - required this.text, - this.icon, - this.isGoogle = false, - required this.onPressed, - }); - - @override - Widget build(BuildContext context) { - return SizedBox( - height: 56, - child: OutlinedButton( - onPressed: onPressed, - style: OutlinedButton.styleFrom( - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - foregroundColor: AppColors.krowCharcoal, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (text.contains('Apple')) - const FaIcon( - FontAwesomeIcons.apple, - color: Colors.black, - size: 20, - ) - else if (isGoogle) - const FaIcon( - FontAwesomeIcons.google, - color: Colors.black, - size: 20, - ) - else - Icon(icon, color: AppColors.krowCharcoal, size: 20), - const SizedBox(width: 12), - Text( - text, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_sign_up_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_sign_up_screen.dart deleted file mode 100644 index f0ae3771..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/auth/client_sign_up_screen.dart +++ /dev/null @@ -1,463 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class ClientSignUpScreen extends StatefulWidget { - const ClientSignUpScreen({super.key}); - - @override - State createState() => _ClientSignUpScreenState(); -} - -class _ClientSignUpScreenState extends State { - final _companyController = TextEditingController(); - final _emailController = TextEditingController(); - final _passwordController = TextEditingController(); - final _confirmPasswordController = TextEditingController(); - bool _obscurePassword = true; - bool _isLoading = false; - - void _handleSignUp() async { - setState(() => _isLoading = true); - // Simulate sign up - await Future.delayed(const Duration(seconds: 1)); - if (mounted) { - setState(() => _isLoading = false); - context.go('/client-home'); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBlue, - body: SafeArea( - bottom: false, - child: Column( - children: [ - // Header - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - ), - ), - ), - ], - ), - ), - - Padding( - padding: const EdgeInsets.only(bottom: 24), - child: Image.network( - 'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png', - height: 40, - fit: BoxFit.contain, - ), - ), - - // Form Card - Expanded( - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - ), - padding: const EdgeInsets.fromLTRB(24, 32, 24, 0), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Create Account', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - 'Get started with Krow for your business', - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 24), - - // Company Name Field - const Text( - 'Company Name', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _companyController, - decoration: InputDecoration( - hintText: 'Enter company name', - prefixIcon: const Icon( - LucideIcons.building2, - color: AppColors.krowMuted, - size: 20, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - const SizedBox(height: 20), - - // Email Field - const Text( - 'Email', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _emailController, - decoration: InputDecoration( - hintText: 'Enter your email', - prefixIcon: const Icon( - LucideIcons.mail, - color: AppColors.krowMuted, - size: 20, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - const SizedBox(height: 20), - - // Password Field - const Text( - 'Password', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _passwordController, - obscureText: _obscurePassword, - decoration: InputDecoration( - hintText: 'Create a password', - prefixIcon: const Icon( - LucideIcons.lock, - color: AppColors.krowMuted, - size: 20, - ), - suffixIcon: IconButton( - icon: Icon( - _obscurePassword - ? LucideIcons.eyeOff - : LucideIcons.eye, - color: AppColors.krowMuted, - size: 20, - ), - onPressed: () => setState( - () => _obscurePassword = !_obscurePassword, - ), - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - const SizedBox(height: 20), - - // Confirm Password Field - const Text( - 'Confirm Password', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _confirmPasswordController, - obscureText: _obscurePassword, - decoration: InputDecoration( - hintText: 'Confirm your password', - prefixIcon: const Icon( - LucideIcons.lock, - color: AppColors.krowMuted, - size: 20, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - - const SizedBox(height: 32), - - // Create Account Button - SizedBox( - height: 56, - child: ElevatedButton( - onPressed: _isLoading ? null : _handleSignUp, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: _isLoading - ? const CircularProgressIndicator( - color: Colors.white, - ) - : const Text( - 'Create Account', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - ), - ), - ), - - const SizedBox(height: 24), - - // Divider - const Row( - children: [ - Expanded(child: Divider(color: AppColors.krowBorder)), - Padding( - padding: EdgeInsets.symmetric(horizontal: 16), - child: Text( - 'or', - style: TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - ), - Expanded(child: Divider(color: AppColors.krowBorder)), - ], - ), - - const SizedBox(height: 24), - - // Social Buttons - _SocialButton( - text: 'Sign Up with Apple', - icon: Icons.apple, - onPressed: () {}, - ), - const SizedBox(height: 12), - _SocialButton( - text: 'Sign Up with Google', - icon: null, - isGoogle: true, - onPressed: () {}, - ), - - const SizedBox(height: 32), - - // Sign In Link - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - "Already have an account? ", - style: TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - GestureDetector( - onTap: () => context.push('/client-sign-in'), - child: const Text( - 'Sign In', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.w600, - fontSize: 14, - ), - ), - ), - ], - ), - const SizedBox(height: 40), - ], - ), - ), - ), - ), - ], - ), - ), - ); - } -} - -class _SocialButton extends StatelessWidget { - final String text; - final IconData? icon; - final bool isGoogle; - final VoidCallback onPressed; - - const _SocialButton({ - required this.text, - this.icon, - this.isGoogle = false, - required this.onPressed, - }); - - @override - Widget build(BuildContext context) { - return SizedBox( - height: 56, - child: OutlinedButton( - onPressed: onPressed, - style: OutlinedButton.styleFrom( - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - foregroundColor: AppColors.krowCharcoal, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (isGoogle) - Container( - width: 20, - height: 20, - decoration: const BoxDecoration(shape: BoxShape.circle), - child: Image.network( - 'https://www.gstatic.com/images/branding/product/1x/gsa_512dp.png', - width: 20, - height: 20, - ), - ) - else if (text.contains('Apple')) - Image.network( - 'https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/480px-Apple_logo_black.svg.png', - height: 24, - ) - else - Icon(icon, color: AppColors.krowCharcoal, size: 20), - const SizedBox(width: 12), - Text( - text, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_billing_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_billing_screen.dart deleted file mode 100644 index 633a21e1..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_billing_screen.dart +++ /dev/null @@ -1,990 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class ClientBillingScreen extends StatefulWidget { - const ClientBillingScreen({super.key}); - - @override - State createState() => _ClientBillingScreenState(); -} - -class _ClientBillingScreenState extends State - with SingleTickerProviderStateMixin { - late TabController _periodTabController; - - // Mock Data - final double currentBill = 4250.00; - final double savings = 320.00; - - final List> pendingInvoices = [ - { - 'id': 'INV-PEND-001', - 'title': 'Server Staff - Downtown Event', - 'location_address': '123 Main St, City Center', - 'client_name': 'TechCorp Inc.', - 'date': '2024-01-24', // Use a recent date - 'invoiceTotal': 840.00, - 'workers_count': 3, - 'total_hours': 24.0, - }, - { - 'id': 'INV-PEND-002', - 'title': 'Bartenders - Private Party', - 'location_address': '456 High St, West End', - 'client_name': 'TechCorp Inc.', - 'date': '2024-01-23', - 'invoiceTotal': 620.00, - 'workers_count': 2, - 'total_hours': 16.0, - } - ]; - - final List> breakdown = [ - {'category': 'Server Staff', 'hours': 120, 'amount': 2160.00}, - {'category': 'Bartenders', 'hours': 80, 'amount': 1520.00}, - {'category': 'Kitchen Staff', 'hours': 40, 'amount': 640.00}, - {'category': 'Event Staff', 'hours': 25, 'amount': 425.00}, - ]; - - final List> invoices = [ - { - 'id': 'INV-2024-012', - 'date': '2024-12-15', - 'amount': 5280.00, - 'status': 'paid' - }, - { - 'id': 'INV-2024-011', - 'date': '2024-12-08', - 'amount': 4850.00, - 'status': 'paid' - }, - { - 'id': 'INV-2024-010', - 'date': '2024-12-01', - 'amount': 4120.00, - 'status': 'paid' - }, - ]; - - @override - void initState() { - super.initState(); - _periodTabController = TabController(length: 2, vsync: this); - } - - @override - void dispose() { - _periodTabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - // Colors matching React - const krowBlue = Color(0xFF0A39DF); - const krowYellow = Color(0xFFFFED4A); - const krowCharcoal = Color(0xFF121826); - // const krowMuted = Color(0xFF6A7382); // Already in theme? Using AppColors.krowMuted - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.fromLTRB(20, 60, 20, 20), - color: krowBlue, - child: Column( - children: [ - // Top Bar - Row( - children: [ - GestureDetector( - onTap: () => context.go('/client-home'), - child: Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 16, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Billing', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - const SizedBox(height: 20), - // Current Bill - Column( - children: [ - Text( - 'Current Period', - style: TextStyle( - color: Colors.white.withOpacity(0.7), - fontSize: 12, - ), - ), - const SizedBox(height: 4), - Text( - '\$${currentBill.toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: krowYellow, - borderRadius: BorderRadius.circular(100), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - LucideIcons.trendingDown, - size: 12, - color: krowCharcoal, - ), - const SizedBox(width: 4), - Text( - '\$${savings.toStringAsFixed(0)} saved', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: krowCharcoal, - ), - ), - ], - ), - ), - ], - ), - ], - ), - ), - - // Content - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Pending Invoices - if (pendingInvoices.isNotEmpty) ...[ - Row( - children: [ - Container( - width: 6, - height: 6, - decoration: const BoxDecoration( - color: Colors.orange, - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - const Text( - 'Awaiting Approval', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const SizedBox(width: 8), - Container( - width: 24, - height: 24, - decoration: const BoxDecoration( - color: krowYellow, - shape: BoxShape.circle, - ), - child: Center( - child: Text( - '${pendingInvoices.length}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - ), - ), - ], - ), - const SizedBox(height: 12), - ...pendingInvoices.map( - (invoice) => Padding( - padding: const EdgeInsets.only(bottom: 8), - child: _buildPendingInvoiceCard(invoice), - ), - ), - const SizedBox(height: 16), - ], - - // Payment Method - _buildPaymentMethodCard(krowBlue, krowYellow, krowCharcoal), - const SizedBox(height: 16), - - // Spending Breakdown - _buildBreakdownCard(krowCharcoal), - const SizedBox(height: 16), - - // Savings Card - _buildSavingsCard(krowBlue, krowYellow, krowCharcoal), - const SizedBox(height: 24), - - // Invoice History - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Invoice History', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - TextButton( - onPressed: () {}, - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - child: Row( - children: [ - Text( - 'View all', - style: TextStyle( - fontSize: 12, - color: krowBlue, - fontWeight: FontWeight.w500, - ), - ), - Icon( - LucideIcons.chevronRight, - size: 16, - color: krowBlue, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFE3E6E9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: invoices.asMap().entries.map((entry) { - final index = entry.key; - final invoice = entry.value; - return Column( - children: [ - if (index > 0) - const Divider( - height: 1, - color: Color(0xFFF1F5F9), - ), - _buildInvoiceItem(invoice), - ], - ); - }).toList(), - ), - ), - - const SizedBox(height: 24), - - // Export Button - OutlinedButton.icon( - onPressed: () {}, - style: OutlinedButton.styleFrom( - minimumSize: const Size(double.infinity, 44), - side: const BorderSide(color: Color(0xFFE3E6E9)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - foregroundColor: krowCharcoal, - ), - icon: const Icon(LucideIcons.download, size: 16), - label: const Text( - 'Export All Invoices', - style: TextStyle(fontSize: 14), - ), - ), - const SizedBox(height: 24), - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildPendingInvoiceCard(Map invoice) { - const krowBlue = Color(0xFF0A39DF); - const krowCharcoal = Color(0xFF121826); - - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFE3E6E9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Address - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 14, - color: Color(0xFF475569), - ), - const SizedBox(width: 4), - Expanded( - child: Text( - invoice['location_address'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF475569), - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - const SizedBox(height: 4), - // Title - Text( - invoice['title'], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const SizedBox(height: 4), - // Client & Date - Row( - children: [ - Text( - invoice['client_name'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - ), - const SizedBox(width: 6), - const Text( - '•', - style: TextStyle(fontSize: 12, color: Color(0xFF94A3B8)), - ), - const SizedBox(width: 6), - Text( - invoice['date'], // Should ideally format date - style: const TextStyle( - fontSize: 12, - color: Color(0xFF475569), - ), - ), - ], - ), - const SizedBox(height: 8), - // Status - Row( - children: [ - Container( - width: 6, - height: 6, - decoration: const BoxDecoration( - color: Colors.orange, - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 6), - const Text( - 'PENDING APPROVAL', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.orange, - letterSpacing: 0.5, - ), - ), - ], - ), - const SizedBox(height: 12), - // Grid Stats - Container( - padding: const EdgeInsets.symmetric(vertical: 10), - decoration: const BoxDecoration( - border: Border.symmetric( - horizontal: BorderSide(color: Color(0xFFF1F5F9)), - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - children: [ - const Icon( - LucideIcons.dollarSign, - size: 14, - color: Color(0xFF94A3B8), - ), - const SizedBox(height: 2), - Text( - '\$${invoice['invoiceTotal'].toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const Text( - 'Total', - style: TextStyle( - fontSize: 10, - color: Color(0xFF64748B), - ), - ), - ], - ), - ), - Container(width: 1, height: 30, color: const Color(0xFFF1F5F9)), - Expanded( - child: Column( - children: [ - const Icon( - LucideIcons.users, - size: 14, - color: Color(0xFF94A3B8), - ), - const SizedBox(height: 2), - Text( - '${invoice['workers_count']}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const Text( - 'workers', - style: TextStyle( - fontSize: 10, - color: Color(0xFF64748B), - ), - ), - ], - ), - ), - Container(width: 1, height: 30, color: const Color(0xFFF1F5F9)), - Expanded( - child: Column( - children: [ - const Icon( - LucideIcons.clock, - size: 14, - color: Color(0xFF94A3B8), - ), - const SizedBox(height: 2), - Text( - '${invoice['total_hours'].toStringAsFixed(1)}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const Text( - 'HRS', - style: TextStyle( - fontSize: 10, - color: Color(0xFF64748B), - ), - ), - ], - ), - ), - ], - ), - ), - const SizedBox(height: 12), - // Approve Button - ElevatedButton( - onPressed: () {}, - style: ElevatedButton.styleFrom( - backgroundColor: krowBlue, - foregroundColor: Colors.white, - minimumSize: const Size(double.infinity, 36), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.checkCircle, size: 16), - SizedBox(width: 6), - Text( - 'Review & Approve', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600), - ), - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildPaymentMethodCard( - Color krowBlue, - Color krowYellow, - Color krowCharcoal, - ) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFE3E6E9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Payment Method', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - TextButton.icon( - onPressed: () {}, - icon: Icon(LucideIcons.plus, size: 14, color: krowBlue), - label: Text( - 'Add', - style: TextStyle(fontSize: 12, color: krowBlue), - ), - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - ), - ], - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Container( - width: 40, - height: 28, - decoration: BoxDecoration( - color: krowBlue, - borderRadius: BorderRadius.circular(4), - ), - child: const Center( - child: Text( - 'VISA', - style: TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '•••• 4242', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const Text( - 'Expires 12/25', - style: TextStyle( - fontSize: 10, - color: Color(0xFF64748B), - ), - ), - ], - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: krowYellow, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - 'Default', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildBreakdownCard(Color krowCharcoal) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFE3E6E9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'This Period Breakdown', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - Container( - height: 24, - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), - borderRadius: BorderRadius.circular(6), - ), - child: TabBar( - controller: _periodTabController, - isScrollable: true, - indicator: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(4), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 1, - ), - ], - ), - labelColor: krowCharcoal, - unselectedLabelColor: const Color(0xFF64748B), - labelStyle: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - ), - padding: const EdgeInsets.all(2), - indicatorSize: TabBarIndicatorSize.tab, - labelPadding: const EdgeInsets.symmetric(horizontal: 8), - dividerColor: Colors.transparent, - tabs: const [Tab(text: 'Week'), Tab(text: 'Month')], - ), - ), - ], - ), - const SizedBox(height: 8), - ...breakdown.map((item) => _buildBreakdownRow(item, krowCharcoal)), - const Padding( - padding: EdgeInsets.symmetric(vertical: 8), - child: Divider(height: 1, color: Color(0xFFE2E8F0)), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Total', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - Text( - '\$${breakdown.fold(0.0, (sum, item) => sum + (item['amount'] as double)).toStringAsFixed(2)}', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildBreakdownRow(Map item, Color krowCharcoal) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 6), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item['category'], - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: krowCharcoal, - ), - ), - Text( - '${item['hours']} hours', - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - Text( - '\$${(item['amount'] as double).toStringAsFixed(2)}', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: krowCharcoal, - ), - ), - ], - ), - ); - } - - Widget _buildSavingsCard( - Color krowBlue, - Color krowYellow, - Color krowCharcoal, - ) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: krowYellow.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: krowYellow), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: krowYellow, - borderRadius: BorderRadius.circular(8), - ), - child: Icon(LucideIcons.trendingDown, size: 16, color: krowCharcoal), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Rate Optimization', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - const SizedBox(height: 4), - const Text( - 'Save \$180/month by switching 3 shifts', - style: TextStyle(fontSize: 12, color: Color(0xFF475569)), - ), - const SizedBox(height: 8), - SizedBox( - height: 28, - child: ElevatedButton( - onPressed: () {}, - style: ElevatedButton.styleFrom( - backgroundColor: krowBlue, - foregroundColor: Colors.white, - elevation: 0, - padding: const EdgeInsets.symmetric(horizontal: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: const Text( - 'View Details', - style: TextStyle(fontSize: 10), - ), - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildInvoiceItem(Map invoice) { - const krowCharcoal = Color(0xFF121826); - const krowBlue = Color(0xFF0A39DF); - - return Padding( - padding: const EdgeInsets.all(12), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), - borderRadius: BorderRadius.circular(8), - ), - child: const Icon( - LucideIcons.fileText, - size: 16, - color: Color(0xFF64748B), - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - invoice['id'], - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: krowCharcoal, - ), - ), - Text( - invoice['date'], // Should format date - style: const TextStyle( - fontSize: 10, - color: Color(0xFF64748B), - ), - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '\$${(invoice['amount'] as double).toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: krowCharcoal, - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: krowBlue.withOpacity(0.1), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - invoice['status'].toString().toUpperCase(), - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: krowBlue, - ), - ), - ), - ], - ), - const SizedBox(width: 8), - const Icon(LucideIcons.download, size: 16, color: Color(0xFF94A3B8)), - ], - ), - ); - } -} \ No newline at end of file diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_coverage_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_coverage_screen.dart deleted file mode 100644 index c64398f6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_coverage_screen.dart +++ /dev/null @@ -1,967 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class ClientCoverageScreen extends StatefulWidget { - const ClientCoverageScreen({super.key}); - - @override - State createState() => _ClientCoverageScreenState(); -} - -class _ClientCoverageScreenState extends State { - DateTime _selectedDate = DateTime.now(); - late DateTime _today; - - // Mock Data - final List> _shifts = [ - { - 'id': '1', - 'title': 'Banquet Server', - 'location': 'Grand Ballroom', - 'startTime': '16:00', // 4:00 PM - 'workersNeeded': 10, - 'date': DateTime.now().toIso8601String().split('T')[0], - 'workers': [ - { - 'name': 'Sarah Wilson', - 'status': 'confirmed', - 'checkInTime': '15:55', - }, - {'name': 'Mike Ross', 'status': 'confirmed', 'checkInTime': '16:00'}, - { - 'name': 'Jane Doe', - 'status': 'confirmed', - 'checkInTime': null, - }, // En route - {'name': 'John Smith', 'status': 'late', 'checkInTime': null}, - ], - }, - { - 'id': '2', - 'title': 'Bartender', - 'location': 'Lobby Bar', - 'startTime': '17:00', // 5:00 PM - 'workersNeeded': 4, - 'date': DateTime.now().toIso8601String().split('T')[0], - 'workers': [ - { - 'name': 'Emily Blunt', - 'status': 'confirmed', - 'checkInTime': '16:45', - }, - { - 'name': 'Chris Evans', - 'status': 'confirmed', - 'checkInTime': '16:50', - }, - { - 'name': 'Tom Holland', - 'status': 'confirmed', - 'checkInTime': null, - }, // En route - ], - }, - ]; - - @override - void initState() { - super.initState(); - _today = DateTime.now(); - _today = DateTime(_today.year, _today.month, _today.day); - } - - List _getCalendarDays() { - final List days = []; - final startDate = _selectedDate.subtract(const Duration(days: 3)); - for (int i = 0; i < 7; i++) { - days.add(startDate.add(Duration(days: i))); - } - return days; - } - - String _formatTime(String? time) { - if (time == null) return ''; - final parts = time.split(':'); - final dt = DateTime(2022, 1, 1, int.parse(parts[0]), int.parse(parts[1])); - return DateFormat('h:mm a').format(dt); - } - - @override - Widget build(BuildContext context) { - // Process mock data for stats - final shiftsToday = _shifts; // In a real app, filter by date - final allApps = shiftsToday - .expand( - (s) => (s['workers'] as List).map((w) => {...w, 'shift_id': s['id']}), - ) - .toList(); - - final totalNeeded = shiftsToday.fold( - 0, - (sum, s) => sum + (s['workersNeeded'] as int), - ); - final confirmedApps = allApps - .where((a) => a['status'] == 'confirmed') - .toList(); - final totalConfirmed = confirmedApps.length; - final coveragePercent = totalNeeded > 0 - ? ((totalConfirmed / totalNeeded) * 100).round() - : 100; - - final lateWorkers = allApps.where((a) => a['status'] == 'late').toList(); - final onTimeWorkers = confirmedApps - .where((a) => a['checkInTime'] != null) - .toList(); - final enRouteWorkers = confirmedApps - .where((a) => a['checkInTime'] == null) - .toList(); - - final calendarDays = _getCalendarDays(); - - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 24, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF2563EB), // blue-600 - Color(0xFF0891B2), // cyan-600 - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.go('/client-home'), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Daily Coverage', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: Colors.transparent, - borderRadius: BorderRadius.circular(8), - ), - child: IconButton( - onPressed: () { - setState(() { - // refresh logic - }); - }, - icon: const Icon( - LucideIcons.refreshCw, - color: Colors.white, - size: 16, - ), - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - style: IconButton.styleFrom( - hoverColor: Colors.white.withOpacity(0.2), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - ), - ), - ], - ), - - const SizedBox(height: 16), - - // Calendar Selector - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _NavButton( - text: '← Prev Week', - onTap: () { - setState(() { - _selectedDate = _selectedDate.subtract( - const Duration(days: 7), - ); - }); - }, - ), - _NavButton( - text: 'Today', - onTap: () { - setState(() { - final now = DateTime.now(); - _selectedDate = DateTime( - now.year, - now.month, - now.day, - ); - }); - }, - ), - _NavButton( - text: 'Next Week →', - onTap: () { - setState(() { - _selectedDate = _selectedDate.add( - const Duration(days: 7), - ); - }); - }, - ), - ], - ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: calendarDays.map((date) { - final isSelected = - date.year == _selectedDate.year && - date.month == _selectedDate.month && - date.day == _selectedDate.day; - final isToday = - date.year == _today.year && - date.month == _today.month && - date.day == _today.day; - - return GestureDetector( - onTap: () { - setState(() { - _selectedDate = date; - }); - }, - child: Container( - width: 44, // roughly grid-cols-7 spacing - height: 60, - decoration: BoxDecoration( - color: isSelected - ? Colors.white - : Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - border: isToday && !isSelected - ? Border.all(color: Colors.white, width: 2) - : null, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - date.day.toString().padLeft(2, '0'), - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: isSelected - ? const Color(0xFF0A39DF) - : Colors.white, - ), - ), - Text( - DateFormat('E').format(date), - style: TextStyle( - fontSize: 9, - fontWeight: FontWeight.w500, - color: isSelected - ? const Color(0xFF6A7382) - : Colors.white.withOpacity(0.7), - ), - ), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - - const SizedBox(height: 16), - - // Compact Coverage Summary - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Coverage Status', - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.7), - ), - ), - Text( - '$coveragePercent%', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - 'Workers', - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.7), - ), - ), - Text( - '$totalConfirmed/$totalNeeded', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - - // Content Body - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - // Quick Stats - Row( - children: [ - Expanded( - child: _QuickStatCard( - value: '${onTimeWorkers.length}', - label: 'Checked In', - valueColor: const Color(0xFF059669), // emerald-600 - ), - ), - const SizedBox(width: 12), - Expanded( - child: _QuickStatCard( - value: '${enRouteWorkers.length}', - label: 'En Route', - valueColor: const Color(0xFFD97706), // amber-600 - ), - ), - const SizedBox(width: 12), - Expanded( - child: _QuickStatCard( - value: '${lateWorkers.length}', - label: 'Late', - valueColor: const Color(0xFFDC2626), // red-600 - ), - ), - ], - ), - - // Alerts - if (lateWorkers.isNotEmpty) ...[ - const SizedBox(height: 20), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - Color(0xFFFEF2F2), // red-50 - Color(0xFFFFF1F2), // rose-50 - ], - begin: Alignment.centerLeft, - end: Alignment.centerRight, - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFFEE2E2), - ), // red-100 - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 2, - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - LucideIcons.alertTriangle, - color: Color(0xFFEF4444), // red-500 - size: 20, - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '${lateWorkers.length} worker(s) running late', - style: const TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFFB91C1C), // red-700 - fontSize: 14, - ), - ), - const SizedBox(height: 4), - const Text( - 'Auto-backup system activated - finding replacements', - style: TextStyle( - fontSize: 14, - color: Color(0xFFDC2626), // red-600 - ), - ), - ], - ), - ), - ], - ), - ), - ], - - const SizedBox(height: 20), - - // Live Activity Header - const Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - 'Live Activity', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - ], - ), - const SizedBox(height: 12), - - // Shifts List - if (shiftsToday.isEmpty) - Container( - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 2, - ), - ], - ), - child: const Column( - children: [ - Icon( - LucideIcons.users, - size: 48, - color: Color(0xFFCBD5E1), - ), // slate-300 - SizedBox(height: 12), - Text( - 'No shifts scheduled for this day', - style: TextStyle( - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ) - else - ...shiftsToday.map((shift) { - final shiftApps = (shift['workers'] as List); - final workersNeeded = shift['workersNeeded'] as int; - final coverage = workersNeeded > 0 - ? ((shiftApps.length / workersNeeded) * 100).round() - : 100; - - return Container( - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 2, - ), - ], - ), - clipBehavior: Clip.antiAlias, - child: Column( - children: [ - // Shift Header - Container( - padding: const EdgeInsets.all(16), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFFEFF6FF), // blue-50 - Color(0xFFECFEFF), // cyan-50 - ], - begin: Alignment.centerLeft, - end: Alignment.centerRight, - ), - border: Border( - bottom: BorderSide( - color: Color(0xFFE2E8F0), - ), // slate-200 - ), - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - width: 8, - height: 8, - decoration: const BoxDecoration( - color: Color( - 0xFF3B82F6, - ), // blue-500 - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - Text( - shift['title'], - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Color( - 0xFF0F172A, - ), // slate-900 - fontSize: 16, - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: Color(0xFF475569), - ), // slate-600 - const SizedBox(width: 4), - Text( - shift['location'], - style: const TextStyle( - fontSize: 12, - color: Color( - 0xFF475569, - ), // slate-600 - ), - ), - const SizedBox(width: 12), - const Icon( - LucideIcons.clock, - size: 12, - color: Color(0xFF475569), - ), - const SizedBox(width: 4), - Text( - _formatTime( - shift['startTime'], - ), - style: const TextStyle( - fontSize: 12, - color: Color(0xFF475569), - ), - ), - ], - ), - ], - ), - ), - _CoverageBadge( - current: shiftApps.length, - total: workersNeeded, - coveragePercent: coverage, - ), - ], - ), - ), - - // Workers List - if (shiftApps.isNotEmpty) - Padding( - padding: const EdgeInsets.all(12), - child: Column( - children: shiftApps.map((worker) { - final isLast = worker == shiftApps.last; - return Padding( - padding: EdgeInsets.only( - bottom: isLast ? 0 : 8, - ), - child: _WorkerRow( - name: worker['name'], - status: worker['status'], - checkInTime: worker['checkInTime'], - formatTime: _formatTime, - shiftStartTime: _formatTime( - shift['startTime'], - ), - ), - ); - }).toList(), - ), - ) - else - const Padding( - padding: EdgeInsets.all(16), - child: Text( - 'No workers assigned yet', - style: TextStyle( - color: Color(0xFF64748B), // slate-500 - fontSize: 14, - ), - ), - ), - ], - ), - ); - }), - - const SizedBox(height: 80), // Bottom padding - ], - ), - ), - ), - ], - ), - ), - ); - } -} - -class _NavButton extends StatelessWidget { - final String text; - final VoidCallback onTap; - - const _NavButton({required this.text, required this.onTap}); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(8), - ), - child: Text( - text, - style: const TextStyle(color: Colors.white, fontSize: 14), - ), - ), - ); - } -} - -class _QuickStatCard extends StatelessWidget { - final String value; - final String label; - final Color valueColor; - - const _QuickStatCard({ - required this.value, - required this.label, - required this.valueColor, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular( - 12, - ), // rounded-xl check? React uses default which is usually 0.5rem(8px) or 0.75rem(12px) for Card - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), // shadow-md - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - Text( - value, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: valueColor, - ), - ), - Text( - label, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ); - } -} - -class _CoverageBadge extends StatelessWidget { - final int current; - final int total; - final int coveragePercent; - - const _CoverageBadge({ - required this.current, - required this.total, - required this.coveragePercent, - }); - - @override - Widget build(BuildContext context) { - Color bg; - Color text; - - if (coveragePercent >= 100) { - bg = const Color(0xFF10B981); // emerald-500 - text = Colors.white; - } else if (coveragePercent >= 80) { - bg = const Color(0xFFF59E0B); // amber-500 - text = Colors.white; - } else { - bg = const Color(0xFFEF4444); // red-500 - text = Colors.white; - } - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2), - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(100), // rounded-full - ), - child: Text( - '$current/$total', - style: TextStyle( - color: text, - fontSize: 12, - fontWeight: FontWeight.w500, - ), - ), - ); - } -} - -class _WorkerRow extends StatelessWidget { - final String name; - final String status; - final String? checkInTime; - final String Function(String?) formatTime; - final String shiftStartTime; - - const _WorkerRow({ - required this.name, - required this.status, - required this.checkInTime, - required this.formatTime, - required this.shiftStartTime, - }); - - @override - Widget build(BuildContext context) { - Color bg; - Color border; - Color textBg; - Color textColor; - IconData icon; - String statusText; - Color badgeBg; - Color badgeText; - String badgeLabel; - - if (status == 'confirmed' && checkInTime != null) { - // Checked In - bg = const Color(0xFFECFDF5); // emerald-50 - border = const Color(0xFF10B981); // emerald-500 - textBg = const Color(0xFFD1FAE5); // emerald-100 - textColor = const Color(0xFF047857); // emerald-700 - icon = LucideIcons.checkCircle; - statusText = '✓ Checked In at ${formatTime(checkInTime)}'; - badgeBg = const Color(0xFF10B981); // emerald-500 - badgeText = Colors.white; - badgeLabel = 'On Site'; - } else if (status == 'confirmed' && checkInTime == null) { - // En Route - bg = const Color(0xFFFFFBEB); // amber-50 - border = const Color(0xFFF59E0B); // amber-500 - textBg = const Color(0xFFFEF3C7); // amber-100 - textColor = const Color(0xFFB45309); // amber-700 - icon = LucideIcons.clock; - statusText = 'En Route - Expected $shiftStartTime'; - badgeBg = const Color(0xFFF59E0B); // amber-500 - badgeText = Colors.white; - badgeLabel = 'En Route'; - } else { - // Late - bg = const Color(0xFFFEF2F2); // red-50 - border = const Color(0xFFEF4444); // red-500 - textBg = const Color(0xFFFEE2E2); // red-100 - textColor = const Color(0xFFB91C1C); // red-700 - icon = LucideIcons.alertTriangle; - statusText = '⚠ Running Late'; - badgeBg = const Color(0xFFEF4444); // red-500 - badgeText = Colors.white; - badgeLabel = 'Late'; - } - - return Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: border, width: 2), - ), - child: CircleAvatar( - backgroundColor: textBg, - child: Text( - name.isNotEmpty ? name[0] : 'W', - style: TextStyle( - color: textColor, - fontWeight: FontWeight.w600, - fontSize: 16, - ), - ), - ), - ), - Positioned( - bottom: -2, - right: -2, - child: Container( - width: 16, - height: 16, - decoration: BoxDecoration( - color: border, - shape: BoxShape.circle, - ), - child: Icon(icon, size: 10, color: Colors.white), - ), - ), - ], - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - Text( - statusText, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: textColor, - ), - ), - ], - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: badgeBg, - borderRadius: BorderRadius.circular(100), // rounded-full - ), - child: Text( - badgeLabel, - style: TextStyle( - color: badgeText, - fontSize: 10, // xs - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_home_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_home_screen.dart deleted file mode 100644 index d4dc8486..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_home_screen.dart +++ /dev/null @@ -1,1958 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; -import 'coverage_dashboard.dart'; - -class ClientHomeScreen extends StatefulWidget { - const ClientHomeScreen({super.key}); - - @override - State createState() => _ClientHomeScreenState(); -} - -class _ClientHomeScreenState extends State { - bool _editMode = false; - bool _showOrderFormSheet = false; - Map? _reorderShiftData; - - // Default widget order - Matched to React DEFAULT_WIDGETS - List _widgetOrder = [ - 'actions', - 'reorder', - 'coverage', - 'spending', - 'liveActivity', - ]; - - // Widget visibility state - final Map _widgetVisibility = { - 'actions': true, - 'reorder': true, - 'coverage': true, - 'spending': true, - 'liveActivity': true, - }; - - final Map _widgetTitles = { - 'actions': 'Quick Actions', - 'reorder': 'Reorder', - 'coverage': 'Today\'s Coverage', - 'spending': 'Spending Insights', - 'liveActivity': 'Live Activity', - }; - - void _toggleWidget(String id) { - setState(() { - _widgetVisibility[id] = !(_widgetVisibility[id] ?? true); - }); - } - - void _resetLayout() { - setState(() { - _widgetOrder = ['actions', 'coverage', 'spending', 'liveActivity']; - for (var key in _widgetVisibility.keys) { - _widgetVisibility[key] = true; - } - }); - } - - void _openOrderFormSheet(Map shiftData) { - setState(() { - _reorderShiftData = shiftData; - _showOrderFormSheet = true; - }); - - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) { - return _ShiftOrderFormSheet( - initialData: _reorderShiftData, - onSubmit: (data) { - // TODO: Handle form submission (create new shift) - Navigator.pop(context); // Close the sheet - setState(() { - _showOrderFormSheet = false; - _reorderShiftData = null; - }); - // Show a success message or refresh data - }, - ); - }, - ).whenComplete(() { - // This is called when the sheet is dismissed (e.g., by swiping down) - setState(() { - _showOrderFormSheet = false; - _reorderShiftData = null; - }); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: SafeArea( - child: Column( - children: [ - // Header - _buildHeader(), - - // Edit Mode Banner - AnimatedContainer( - duration: const Duration(milliseconds: 300), - height: _editMode ? 76 : 0, // Adjusted height for correct padding - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: _editMode - ? Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - border: Border.all( - color: AppColors.krowBlue.withOpacity(0.3), - ), - borderRadius: BorderRadius.circular(12), // rounded-xl - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - const Icon( - LucideIcons.edit3, - size: 16, - color: AppColors.krowBlue, - ), - const SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Edit Mode Active', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - Text( - 'Drag to reorder, toggle visibility', - style: TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - TextButton( - onPressed: _resetLayout, - style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 4, - ), - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - backgroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - 12, - ), // rounded-xl - side: BorderSide(color: AppColors.krowBorder), - ), - ), - child: const Text( - 'Reset', - style: TextStyle( - fontSize: 12, - color: AppColors.krowCharcoal, - ), - ), - ), - ], - ), - ) - : const SizedBox.shrink(), - ), - - // Scrollable Content - Expanded( - child: _editMode - ? ReorderableListView( - padding: const EdgeInsets.only( - bottom: 100, - left: 16, - right: 16, - ), - onReorder: (oldIndex, newIndex) { - setState(() { - if (oldIndex < newIndex) { - newIndex -= 1; - } - final String item = _widgetOrder.removeAt(oldIndex); - _widgetOrder.insert(newIndex, item); - }); - }, - children: _widgetOrder.map((id) { - return Container( - key: ValueKey(id), - margin: const EdgeInsets.only(bottom: 16), - child: _buildDraggableWidgetWrapper(id), - ); - }).toList(), - ) - : ListView( - padding: const EdgeInsets.only( - bottom: 100, - left: 16, - right: 16, - ), - children: _widgetOrder.map((id) { - if (!(_widgetVisibility[id] ?? true)) { - return const SizedBox.shrink(); - } - return Padding( - padding: const EdgeInsets.only(bottom: 16), - child: _buildWidgetContent(id), - ); - }).toList(), - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader() { - return Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: AppColors.krowBlue.withOpacity(0.2), - width: 2, - ), - ), - child: CircleAvatar( - backgroundColor: AppColors.krowBlue.withOpacity(0.1), - child: const Text( - 'C', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ), - ), - const SizedBox(width: 10), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Welcome back', - style: TextStyle(color: AppColors.krowMuted, fontSize: 10), - ), - Text( - 'Your Company', - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ], - ), - Row( - children: [ - GestureDetector( - onTap: () { - setState(() { - _editMode = !_editMode; - }); - }, - child: Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: _editMode ? AppColors.krowBlue : Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - ), - ], - ), - child: Icon( - LucideIcons.edit3, - color: _editMode ? Colors.white : AppColors.krowMuted, - size: 16, - ), - ), - ), - const SizedBox(width: 6), - Stack( - children: [ - Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - ), - ], - ), - child: const Icon( - LucideIcons.bell, - color: AppColors.krowMuted, - size: 16, - ), - ), - Positioned( - top: -2, - right: -2, - child: Container( - width: 16, - height: 16, - decoration: const BoxDecoration( - color: Color(0xFFF04444), - shape: BoxShape.circle, - ), - child: const Center( - child: Text( - '3', - style: TextStyle( - color: Colors.white, - fontSize: 9, - fontWeight: FontWeight - .w500, // Changed from FontWeight.bold to FontWeight.w500 - ), - ), - ), - ), - ), - ], - ), - const SizedBox(width: 6), - GestureDetector( - onTap: () => context.push('/client-settings'), - child: Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - ), - ], - ), - child: const Icon( - LucideIcons.settings, - color: AppColors.krowMuted, - size: 16, - ), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildDraggableWidgetWrapper(String id) { - bool isVisible = _widgetVisibility[id] ?? true; - return Column( - children: [ - // Control Header - Row( - children: [ - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: Row( - children: [ - const Icon( - LucideIcons.gripVertical, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Text( - _widgetTitles[id] ?? '', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ), - const SizedBox(width: 8), - GestureDetector( - onTap: () => _toggleWidget(id), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: Icon( - isVisible ? LucideIcons.eye : LucideIcons.eyeOff, - size: 14, - color: isVisible ? AppColors.krowBlue : AppColors.krowMuted, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - // Widget Content (Dimmed if hidden) - Opacity( - opacity: isVisible ? 1.0 : 0.4, - child: IgnorePointer( - ignoring: !isVisible, - child: _buildWidgetContent(id), - ), - ), - ], - ); - } - - Widget _buildWidgetContent(String id) { - switch (id) { - case 'actions': - return const _ActionsWidget(); - case 'reorder': - return _ReorderWidget(onReorderPressed: _openOrderFormSheet); - case 'spending': - return const _SpendingWidget(); - case 'coverage': - return const _CoverageWidget(); - case 'liveActivity': - return const _LiveActivityWidget(); - default: - return const SizedBox.shrink(); - } - } -} - -// --- WIDGET IMPLEMENTATIONS --- - -class _ActionsWidget extends StatelessWidget { - const _ActionsWidget(); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Expanded( - child: GestureDetector( - onTap: () => context.push('/create-order/rapid'), - child: Container( - height: 100, - padding: const EdgeInsets.all(10), // p-2.5 in React is 10px - decoration: BoxDecoration( - color: const Color(0xFFFEF2F2), // red-50 - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: const Color(0xFFFECACA)), // red-200 - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 4, - ), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: const Color(0xFFFEE2E2), // red-100 - borderRadius: BorderRadius.circular(12), // rounded-xl - ), - child: const Icon( - LucideIcons.zap, // Zap - color: Color(0xFFDC2626), // text-red-600 - size: 16, // w-4 h-4 - ), - ), - const SizedBox(height: 6), // gap-1.5 in React is 6px - const Text( - 'RAPID', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: Color(0xFF7F1D1D), // red-900 - ), - ), - const Text( - 'Urgent same-day', - style: TextStyle( - fontSize: 8, - color: Color(0xFFB91C1C), // red-700 - ), - ), - ], - ), - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: GestureDetector( - onTap: () => context.push('/create-order'), - child: Container( - height: 100, - padding: const EdgeInsets.all(10), // p-2.5 in React is 10px - decoration: BoxDecoration( - color: Colors.white, // bg-white - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all( - color: const Color(0xFFE2E8F0), - ), // border border-slate-200 - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 4, - ), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), // bg-blue-50 - borderRadius: BorderRadius.circular(12), // rounded-xl - ), - child: const Icon( - LucideIcons.plus, // Plus - color: Color(0xFF2563EB), // text-blue-600 - size: 16, - ), - ), - const SizedBox(height: 6), // gap-1.5 in React is 6px - const Text( - 'Create Order', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const Text( - 'Schedule shifts', - style: TextStyle( - fontSize: 8, - color: Color(0xFF475569), // slate-600 - ), - ), - ], - ), - ), - ), - ), - ], - ); - } -} - -class _ReorderWidget extends StatelessWidget { - final Function(Map shiftData) onReorderPressed; - - const _ReorderWidget({required this.onReorderPressed}); - - @override - Widget build(BuildContext context) { - // Mock recent orders - final recentOrders = [ - { - 'title': 'Server', - 'location': 'Downtown Restaurant', - 'hourlyRate': 18.0, - 'hours': 6, - 'workers': 3, - 'type': 'One Day', - 'startTime': '17:00', - 'endTime': '23:00', - 'locationAddress': '123 Main St, City', - }, - { - 'title': 'Bartender', - 'location': 'Rooftop Bar', - 'hourlyRate': 22.0, - 'hours': 7, - 'workers': 2, - 'type': 'One Day', - 'startTime': '19:00', - 'endTime': '02:00', - 'locationAddress': '456 High St, City', - }, - { - 'title': 'Event Staff', - 'location': 'Convention Center', - 'hourlyRate': 20.0, - 'hours': 10, - 'workers': 5, - 'type': 'Multi-Day', - 'startTime': '08:00', - 'endTime': '18:00', - 'locationAddress': '789 Event Blvd, City', - }, - ]; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'REORDER', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - letterSpacing: 0.5, - ), - ), - const SizedBox(height: 8), - SizedBox( - height: 140, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: recentOrders.length, - separatorBuilder: (context, index) => const SizedBox(width: 12), - itemBuilder: (context, index) { - final order = recentOrders[index]; - final totalCost = - (order['hourlyRate'] as double) * - (order['hours'] as int) * - (order['workers'] as int); - - return Container( - width: 260, - padding: const EdgeInsets.all(10), // p-2.5 in React is 10px - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 4, - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Row( - children: [ - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - borderRadius: BorderRadius.circular( - 12, - ), // rounded-xl - ), - child: const Icon( - LucideIcons.briefcase, - size: 16, - color: AppColors.krowBlue, - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - order['title'] as String, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - overflow: TextOverflow.ellipsis, - ), - Text( - order['location'] as String, - style: const TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '\$${totalCost.toStringAsFixed(0)}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - '\$${order['hourlyRate']}/hr · ${order['hours']}h', - style: const TextStyle( - fontSize: 9, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - const SizedBox(height: 10), - Row( - children: [ - _Badge( - icon: LucideIcons.calendar, - text: order['type'] as String, - color: const Color(0xFF2563EB), // blue-600 - bg: const Color(0xFF2563EB), - textColor: Colors.white, - ), - const SizedBox(width: 6), - _Badge( - icon: LucideIcons.users, - text: '${order['workers']}', - color: const Color(0xFF334155), // slate-700 - bg: const Color(0xFFF1F5F9), // slate-100 - textColor: const Color(0xFF334155), - ), - ], - ), - const Spacer(), - SizedBox( - height: 28, - width: double.infinity, - child: ElevatedButton.icon( - onPressed: () { - onReorderPressed(order); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - padding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - icon: const Icon(LucideIcons.rotateCcw, size: 12), - label: const Text( - 'Reorder', - style: TextStyle(fontSize: 12), - ), - ), - ), - ], - ), - ); - }, - ), - ), - ], - ); - } -} - -class _Badge extends StatelessWidget { - final IconData icon; - final String text; - final Color color; - final Color bg; - final Color textColor; - - const _Badge({ - required this.icon, - required this.text, - required this.color, - required this.bg, - required this.textColor, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: bg == textColor ? bg : bg, - borderRadius: BorderRadius.circular(4), - ), - child: Row( - children: [ - Icon(icon, size: 10, color: bg == textColor ? Colors.white : color), - const SizedBox(width: 4), - Text( - text, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: textColor, - ), - ), - ], - ), - ); - } -} - -class _SpendingWidget extends StatelessWidget { - const _SpendingWidget(); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'SPENDING INSIGHTS', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - letterSpacing: 0.5, - ), - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [AppColors.krowBlue, Color(0xFF0830B8)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: AppColors.krowBlue.withOpacity(0.3), - blurRadius: 4, // shadow-md -> 4 - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'This Week', - style: TextStyle(color: Colors.white70, fontSize: 9), - ), - const SizedBox(height: 4), // mb-1 -> 4 - const Text( - '\$4,250', - style: TextStyle( - color: Colors.white, - fontSize: 24, // text-2xl (24) - fontWeight: FontWeight.bold, - ), - ), - Text( - '12 shifts', - style: TextStyle( - color: Colors.white.withOpacity(0.6), - fontSize: 9, - ), - ), - ], - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - const Text( - 'Next 7 Days', - style: TextStyle(color: Colors.white70, fontSize: 9), - ), - const SizedBox(height: 4), // mb-1 -> 4 - const Text( - '\$6,100', - style: TextStyle( - color: Colors.white, - fontSize: 20, // text-xl (20) - fontWeight: FontWeight.bold, - ), - ), - Text( - '18 scheduled', - style: TextStyle( - color: Colors.white.withOpacity(0.6), - fontSize: 9, - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - Container( - padding: const EdgeInsets.only(top: 12), - decoration: const BoxDecoration( - border: Border(top: BorderSide(color: Colors.white24)), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 24, - height: 24, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.trendingDown, - color: Colors.white, - size: 14, - ), - ), - ), - const SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 Save \$180/month', - style: TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 2), // mb-0.5 -> 2 - Text( - 'Book 48hrs ahead for better rates', - style: TextStyle( - color: Colors.white.withOpacity(0.8), - fontSize: 9, - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ], - ); - } -} - -class _CoverageWidget extends StatelessWidget { - const _CoverageWidget(); - - @override - Widget build(BuildContext context) { - const totalNeeded = 10; - const totalConfirmed = 8; - const coveragePercent = 80; - - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'TODAY\'S COVERAGE', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - letterSpacing: 0.5, - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: const Color(0xFFD1FAE5), // emerald-100 - borderRadius: BorderRadius.circular(12), // rounded-xl - ), - child: const Text( - '$coveragePercent% Covered', - style: TextStyle( - fontSize: 9, - fontWeight: FontWeight.bold, - color: Color(0xFF047857), // emerald-700 - ), - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: _MetricCard( - icon: LucideIcons.target, - iconColor: AppColors.krowBlue, - label: 'Needed', - value: '$totalNeeded', - ), - ), - const SizedBox(width: 8), - Expanded( - child: _MetricCard( - icon: LucideIcons.checkCircle2, - iconColor: const Color(0xFF059669), // emerald-600 - label: 'Filled', - value: '$totalConfirmed', - valueColor: const Color(0xFF059669), // emerald-600 - ), - ), - const SizedBox(width: 8), - Expanded( - child: _MetricCard( - icon: LucideIcons.alertCircle, - iconColor: const Color(0xFFDC2626), // red-600 - label: 'Open', - value: '${totalNeeded - totalConfirmed}', - valueColor: const Color(0xFFDC2626), // red-600 - ), - ), - ], - ), - ], - ); - } -} - -class _MetricCard extends StatelessWidget { - final IconData icon; - final Color iconColor; - final String label; - final String value; - final Color? valueColor; - - const _MetricCard({ - required this.icon, - required this.iconColor, - required this.label, - required this.value, - this.valueColor, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 14, color: iconColor), - const SizedBox(width: 6), - Text( - label, - style: const TextStyle( - fontSize: 9, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - const SizedBox(height: 6), - Text( - value, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: valueColor ?? AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } -} - -class _LiveActivityWidget extends StatelessWidget { - const _LiveActivityWidget(); - - @override - Widget build(BuildContext context) { - // Mock data for CoverageDashboard - final shifts = [ - { - 'workersNeeded': 5, - 'filled': 4, - 'hourlyRate': 20.0, - 'status': 'OPEN', - 'date': DateTime.now().toIso8601String().split('T')[0], - }, - { - 'workersNeeded': 5, - 'filled': 5, - 'hourlyRate': 22.0, - 'status': 'FILLED', - 'date': DateTime.now().toIso8601String().split('T')[0], - }, - ]; - final applications = [ - {'status': 'CONFIRMED', 'checkInTime': '09:00'}, - {'status': 'CONFIRMED', 'checkInTime': '09:05'}, - {'status': 'CONFIRMED'}, // not checked in - {'status': 'LATE'}, // late - ]; - - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'LIVE ACTIVITY', - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - letterSpacing: 0.5, - ), - ), - GestureDetector( - onTap: () => context.push('/client-coverage'), - child: const Text( - 'View all', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: AppColors.krowBlue, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - CoverageDashboard(shifts: shifts, applications: applications), - ], - ); - } -} - -class _ShiftOrderFormSheet extends StatefulWidget { - final Map? initialData; - final Function(Map data) onSubmit; - final bool isLoading; - - const _ShiftOrderFormSheet({ - super.key, - this.initialData, - required this.onSubmit, - this.isLoading = false, - }); - - @override - State<_ShiftOrderFormSheet> createState() => _ShiftOrderFormSheetState(); -} - -class _ShiftOrderFormSheetState extends State<_ShiftOrderFormSheet> { - late Map _formData; - final List _roles = [ - 'Server', - 'Bartender', - 'Busser', - 'Cook', - 'Dishwasher', - 'Event Staff', - 'Warehouse Worker', - 'Retail Associate', - 'Host/Hostess', - ]; - - @override - void initState() { - super.initState(); - final defaultPosition = { - 'title': '', - 'start_time': '', - 'end_time': '', - 'workers_needed': 1, - 'hourly_rate': 18.0, - }; - - final defaults = { - 'date': '', - 'location': '', - 'recurring': false, - 'duration_days': null, - 'permanent': false, - 'duration_months': null, - 'positions': [Map.from(defaultPosition)], - }; - - if (widget.initialData != null) { - final input = widget.initialData!; - // Map keys from recentOrders to form fields - final firstPosition = { - ...defaultPosition, - 'title': input['title'] ?? input['role'] ?? '', - 'start_time': input['startTime'] ?? input['start_time'] ?? '', - 'end_time': input['endTime'] ?? input['end_time'] ?? '', - 'hourly_rate': (input['hourlyRate'] ?? input['hourly_rate'] ?? 18.0) - .toDouble(), - 'workers_needed': (input['workers'] ?? input['workers_needed'] ?? 1) - .toInt(), - }; - - _formData = { - ...defaults, - ...input, - 'positions': [firstPosition], - }; - } else { - _formData = Map.from(defaults); - } - - // Pre-fill date with tomorrow if reordering and date is empty - if (_formData['date'] == null || _formData['date'] == '') { - final tomorrow = DateTime.now().add(const Duration(days: 1)); - _formData['date'] = tomorrow.toIso8601String().split('T')[0]; - } - } - - void _updateField(String field, dynamic value) { - setState(() { - _formData[field] = value; - }); - } - - void _updatePositionField(int index, String field, dynamic value) { - setState(() { - _formData['positions'][index][field] = value; - }); - } - - void _addPosition() { - setState(() { - _formData['positions'].add({ - 'title': '', - 'start_time': '', - 'end_time': '', - 'workers_needed': 1, - 'hourly_rate': 18.0, - }); - }); - } - - void _removePosition(int index) { - if (_formData['positions'].length > 1) { - setState(() { - _formData['positions'].removeAt(index); - }); - } - } - - String _getShiftType() { - if (_formData['permanent'] == true || - _formData['duration_months'] != null) { - return 'Long Term'; - } - if (_formData['recurring'] == true || _formData['duration_days'] != null) { - return 'Multi-Day'; - } - return 'One Day'; - } - - @override - Widget build(BuildContext context) { - return Container( - height: MediaQuery.of(context).size.height * 0.9, - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Column( - children: [ - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.grey.shade200)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.initialData != null - ? 'Edit & Reorder' - : 'Post a New Shift', - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - IconButton( - icon: const Icon(LucideIcons.x, color: AppColors.krowMuted), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ), - if (widget.initialData != null) - Padding( - padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20), - child: Text( - 'Review and edit the details before posting', - style: TextStyle(fontSize: 14, color: Colors.grey.shade600), - ), - ), - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Shift Type Badge - Container( - margin: const EdgeInsets.only(bottom: 20), - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), // blue-50 - borderRadius: BorderRadius.circular(999), // rounded-full - border: Border.all( - color: const Color(0xFFBFDBFE), - ), // blue-200 - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: const Color(0xFF3B82F6), // blue-500 - ), - ), - const SizedBox(width: 8), - Text( - _getShiftType(), - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, // font-semibold - color: Color(0xFF1D4ED8), // blue-700 - ), - ), - ], - ), - ), - - // Date - _buildLabel('Date *'), - _buildInputField( - key: ValueKey('date_${_formData['date']}'), - hintText: 'mm/dd/yyyy', - icon: LucideIcons.calendar, - initialValue: _formData['date'], - onTap: () async { - final selectedDate = await showDatePicker( - context: context, - initialDate: - _formData['date'] != null && - _formData['date'].isNotEmpty - ? DateTime.parse(_formData['date']) - : DateTime.now(), - firstDate: DateTime.now(), - lastDate: DateTime.now().add( - const Duration(days: 365 * 5), - ), - ); - if (selectedDate != null) { - _updateField( - 'date', - selectedDate.toIso8601String().split('T')[0], - ); - } - }, - readOnly: true, - ), - const SizedBox(height: 20), - - // Location - _buildLabel('Location *'), - _buildInputField( - hintText: 'Business address', - icon: LucideIcons.mapPin, - initialValue: _formData['location'], - onChanged: (value) => _updateField('location', value), - ), - const SizedBox(height: 20), - - // Positions Section - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Positions', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - TextButton.icon( - onPressed: _addPosition, - icon: const Icon(LucideIcons.plus, size: 16), - label: const Text('Add Position'), - style: TextButton.styleFrom( - foregroundColor: const Color(0xFF2563EB), // blue-600 - textStyle: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - ), - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - ), - ], - ), - const SizedBox(height: 16), - - // Position Cards - ...(_formData['positions'] as List).asMap().entries.map(( - entry, - ) { - final index = entry.key; - final position = entry.value; - return Padding( - padding: const EdgeInsets.only(bottom: 20), - child: Card( - elevation: 0, - margin: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - side: BorderSide(color: Colors.grey.shade200), - ), - color: Colors.grey.shade50, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: const Color( - 0xFF2563EB, - ), // blue-600 - ), - child: Center( - child: Text( - '${index + 1}', - style: const TextStyle( - color: Colors.white, - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 10), - Text( - 'Position ${index + 1}', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), // slate-700 - ), - ), - ], - ), - if (_formData['positions'].length > 1) - IconButton( - icon: const Icon( - LucideIcons.trash2, - size: 18, - color: Colors.red, - ), - onPressed: () => _removePosition(index), - ), - ], - ), - const SizedBox(height: 20), - - // Role Selection - _buildLabel('Role *', isSmall: true), - DropdownButtonFormField( - value: position['title'].isEmpty - ? null - : position['title'], - hint: const Text('Select role'), - items: _roles.map((role) { - return DropdownMenuItem( - value: role, - child: Text(role), - ); - }).toList(), - onChanged: (value) => - _updatePositionField(index, 'title', value), - icon: const Icon( - LucideIcons.chevronDown, - size: 16, - color: Color(0xFF94A3B8), // slate-400 - ), - decoration: _buildDropdownInputDecoration(), - ), - const SizedBox(height: 20), - - // Time - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - _buildLabel( - 'Start Time *', - isSmall: true, - icon: LucideIcons.clock, - ), - _buildInputField( - key: ValueKey( - 'start_time_${index}_${position['start_time']}', - ), - hintText: 'HH:MM', - initialValue: position['start_time'], - onTap: () async { - final selectedTime = - await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (selectedTime != null) { - _updatePositionField( - index, - 'start_time', - '${selectedTime.hour.toString().padLeft(2, '0')}:${selectedTime.minute.toString().padLeft(2, '0')}', - ); - } - }, - readOnly: true, - ), - ], - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - _buildLabel( - 'End Time *', - isSmall: true, - icon: LucideIcons.clock, - ), - _buildInputField( - key: ValueKey( - 'end_time_${index}_${position['end_time']}', - ), - hintText: 'HH:MM', - initialValue: position['end_time'], - onTap: () async { - final selectedTime = - await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (selectedTime != null) { - _updatePositionField( - index, - 'end_time', - '${selectedTime.hour.toString().padLeft(2, '0')}:${selectedTime.minute.toString().padLeft(2, '0')}', - ); - } - }, - readOnly: true, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 20), - - // Workers Needed - _buildLabel('Number of Workers', isSmall: true), - Row( - children: [ - _buildWorkerCountButton( - icon: LucideIcons.minus, - onPressed: () { - if (position['workers_needed'] > 1) { - _updatePositionField( - index, - 'workers_needed', - position['workers_needed'] - 1, - ); - } - }, - ), - const SizedBox(width: 8), - Expanded( - child: Container( - height: 44, // h-11 - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey.shade300, - ), - borderRadius: BorderRadius.circular( - 8, - ), // rounded-lg - color: Colors.white, - ), - child: Center( - child: Text( - '${position['workers_needed']}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ), - ), - ), - const SizedBox(width: 8), - _buildWorkerCountButton( - icon: LucideIcons.plus, - onPressed: () { - _updatePositionField( - index, - 'workers_needed', - position['workers_needed'] + 1, - ); - }, - ), - ], - ), - const SizedBox(height: 20), - - // Lunch Break - _buildLabel('Lunch Break', isSmall: true), - DropdownButtonFormField( - value: '30', // Default value - items: const [ - DropdownMenuItem( - value: '0', - child: Text('None'), - ), - DropdownMenuItem( - value: '30', - child: Text('30 min (Unpaid)'), - ), - DropdownMenuItem( - value: '60', - child: Text('60 min (Unpaid)'), - ), - ], - onChanged: (value) { - // TODO: Handle lunch break selection - }, - icon: const Icon( - LucideIcons.chevronDown, - size: 16, - color: Color(0xFF94A3B8), // slate-400 - ), - decoration: _buildDropdownInputDecoration(), - ), - const SizedBox(height: 20), - - // Different Location Option - TextButton.icon( - onPressed: () { - // TODO: Implement different location - }, - icon: const Icon(LucideIcons.mapPin, size: 14), - label: const Text( - 'Use different location for this position', - ), - style: TextButton.styleFrom( - foregroundColor: const Color( - 0xFF2563EB, - ), // blue-600 - textStyle: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - ), - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: - MaterialTapTargetSize.shrinkWrap, - ), - ), - ], - ), - ), - ), - ); - }).toList(), - const SizedBox(height: 20), - ], - ), - ), - ), - SafeArea( - top: false, - child: Padding( - padding: const EdgeInsets.all(20), - child: ElevatedButton( - onPressed: - (_formData['date']?.isNotEmpty == true && - _formData['location']?.isNotEmpty == true && - (_formData['positions'] as List).every( - (p) => - p['title']?.isNotEmpty == true && - p['start_time']?.isNotEmpty == true && - p['end_time']?.isNotEmpty == true, - )) - ? () => widget.onSubmit(_formData) - : null, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF2563EB), // blue-600 - foregroundColor: Colors.white, - minimumSize: const Size(double.infinity, 48), // h-12 - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - ), - elevation: 0, - textStyle: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, // font-semibold - ), - ), - child: widget.isLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation( - Colors.white, - ), - ), - ) - : const Text('Post Shift'), - ), - ), - ), - ], - ), - ); - } - - Widget _buildWorkerCountButton({ - required IconData icon, - required VoidCallback onPressed, - }) { - return SizedBox( - width: 44, // w-11 - height: 44, // h-11 - child: OutlinedButton( - onPressed: onPressed, - style: OutlinedButton.styleFrom( - padding: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), // rounded-lg - ), - side: BorderSide(color: Colors.grey.shade300), - foregroundColor: AppColors.krowCharcoal, - backgroundColor: Colors.white, - elevation: 0, - textStyle: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500), - ), - child: Icon(icon, size: 20), - ), - ); - } - - Widget _buildLabel(String text, {bool isSmall = false, IconData? icon}) { - return Padding( - padding: const EdgeInsets.only(bottom: 6), - child: Row( - children: [ - if (icon != null) ...[ - Icon(icon, size: 14, color: AppColors.krowCharcoal), - const SizedBox(width: 4), - ], - Text( - text, - style: TextStyle( - fontSize: isSmall ? 12 : 14, - fontWeight: isSmall - ? FontWeight.w500 - : FontWeight.w600, // font-medium vs font-semibold - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } - - InputDecoration _buildInputDecoration({String? hintText, IconData? icon}) { - return InputDecoration( - hintText: hintText, - hintStyle: const TextStyle(color: Color(0xFF94A3B8)), // slate-400 - filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsets.symmetric(horizontal: 16), - prefixIcon: icon != null - ? Icon(icon, size: 16, color: const Color(0xFF94A3B8)) - : null, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - borderSide: const BorderSide(color: Color(0xFFCBD5E1)), // slate-300 - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - borderSide: const BorderSide(color: Color(0xFFCBD5E1)), // slate-300 - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - borderSide: const BorderSide( - color: Color(0xFF2563EB), - width: 2, - ), // blue-600 - ), - errorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: Colors.red, width: 2), - ), - focusedErrorBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: Colors.red, width: 2), - ), - ); - } - - InputDecoration _buildDropdownInputDecoration() { - return InputDecoration( - filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsets.symmetric(horizontal: 16), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - borderSide: const BorderSide(color: Color(0xFFCBD5E1)), // slate-300 - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - borderSide: const BorderSide(color: Color(0xFFCBD5E1)), // slate-300 - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), // rounded-xl - borderSide: const BorderSide( - color: Color(0xFF2563EB), - width: 2, - ), // blue-600 - ), - ); - } - - Widget _buildInputField({ - Key? key, - String? hintText, - IconData? icon, - String? initialValue, - ValueChanged? onChanged, - GestureTapCallback? onTap, - bool readOnly = false, - }) { - return TextFormField( - key: key, - initialValue: initialValue, - readOnly: readOnly, - onTap: onTap, - onChanged: onChanged, - style: const TextStyle(fontSize: 14, color: AppColors.krowCharcoal), - decoration: _buildInputDecoration(hintText: hintText, icon: icon) - .copyWith( - // Ensure height is consistent h-11 - constraints: const BoxConstraints(minHeight: 44), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_hubs_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_hubs_screen.dart deleted file mode 100644 index fd826473..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_hubs_screen.dart +++ /dev/null @@ -1,753 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; - -class ClientHubsScreen extends StatefulWidget { - const ClientHubsScreen({super.key}); - - @override - State createState() => _ClientHubsScreenState(); -} - -class _ClientHubsScreenState extends State { - // Mock Data - final List> _hubs = []; - bool _showAddHub = false; - bool _showIdentifyNFC = false; - Map? _selectedHub; - String? _nfcTagId; - - final _nameController = TextEditingController(); - final _locationNameController = TextEditingController(); - final _addressController = TextEditingController(); - - void _addHub() { - if (_nameController.text.isEmpty) return; - setState(() { - _hubs.add({ - 'id': DateTime.now().millisecondsSinceEpoch.toString(), - 'name': _nameController.text, - 'locationName': _locationNameController.text, - 'address': _addressController.text, - 'nfcTagId': null, - }); - _nameController.clear(); - _locationNameController.clear(); - _addressController.clear(); - _showAddHub = false; - }); - } - - void _deleteHub(String id) { - setState(() { - _hubs.removeWhere((hub) => hub['id'] == id); - }); - } - - void _simulateNFCScan() { - setState(() { - _nfcTagId = - 'NFC-${DateTime.now().millisecondsSinceEpoch.toString().substring(8).toUpperCase()}'; - }); - } - - void _assignTag() { - if (_selectedHub != null && _nfcTagId != null) { - setState(() { - final index = _hubs.indexWhere((h) => h['id'] == _selectedHub!['id']); - if (index != -1) { - _hubs[index]['nfcTagId'] = _nfcTagId; - } - _showIdentifyNFC = false; - _nfcTagId = null; - _selectedHub = null; - }); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: Stack( - children: [ - CustomScrollView( - slivers: [ - SliverAppBar( - backgroundColor: const Color(0xFF121826), - automaticallyImplyLeading: false, - expandedHeight: 140, - pinned: true, - flexibleSpace: FlexibleSpaceBar( - background: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF121826), Color(0xFF1E293B)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - padding: const EdgeInsets.fromLTRB(20, 48, 20, 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Hubs', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 24, - ), - ), - Text( - 'Manage clock-in locations', - style: TextStyle( - color: Color(0xFFCBD5E1), // slate-300 - fontSize: 14, - ), - ), - ], - ), - ElevatedButton.icon( - onPressed: () => - setState(() => _showAddHub = true), - icon: const Icon( - LucideIcons.plus, - size: 16, - color: Color(0xFF121826), - ), - label: const Text( - 'Add Hub', - style: TextStyle( - color: Color(0xFF121826), - fontWeight: FontWeight.bold, - fontSize: 13, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFFFED4A), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 4, - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), - - SliverPadding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 100), - sliver: SliverList( - delegate: SliverChildListDelegate([ - const SizedBox(height: 12), - ..._hubs.map((hub) => _buildHubCard(hub)), - - if (_hubs.isEmpty) _buildEmptyState(), - - const SizedBox(height: 20), - _buildInfoCard(), - ]), - ), - ), - ], - ), - - if (_showAddHub) _buildAddHubDialog(), - - if (_showIdentifyNFC) _buildIdentifyNFCDialog(), - ], - ), - ); - } - - Widget _buildHubCard(Map hub) { - final bool hasNfc = hub['nfcTagId'] != null; - return Container( - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Container( - width: 52, - height: 52, - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), // blue-50 - borderRadius: BorderRadius.circular(16), - ), - child: Icon( - hasNfc ? LucideIcons.checkCircle : LucideIcons.nfc, - color: hasNfc - ? const Color(0xFF16A34A) - : const Color(0xFF94A3B8), // green-600 or slate-400 - size: 24, - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - hub['name'], - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: Color(0xFF0F172A), - ), - ), - if (hub['locationName'].isNotEmpty) - Text( - hub['locationName'], - style: const TextStyle( - color: Color(0xFF64748B), - fontSize: 12, - ), - ), - if (hub['address'].isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: Color(0xFF94A3B8), - ), - const SizedBox(width: 4), - Expanded( - child: Text( - hub['address'], - style: const TextStyle( - color: Color(0xFF64748B), - fontSize: 12, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ), - if (hasNfc) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - 'Tag: ${hub['nfcTagId']}', - style: const TextStyle( - color: Color(0xFF16A34A), - fontSize: 12, - fontFamily: 'monospace', - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - Row( - children: [ - IconButton( - onPressed: () { - setState(() { - _selectedHub = hub; - _showIdentifyNFC = true; - }); - }, - icon: const Icon( - LucideIcons.nfc, - color: Color(0xFF2563EB), - size: 20, - ), - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - splashRadius: 20, - ), - const SizedBox(width: 8), - IconButton( - onPressed: () => _deleteHub(hub['id']), - icon: const Icon( - LucideIcons.trash2, - color: Color(0xFFDC2626), - size: 20, - ), // red-600 - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - splashRadius: 20, - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildEmptyState() { - return Container( - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: Color(0xFFF1F5F9), // slate-100 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.nfc, - size: 32, - color: Color(0xFF94A3B8), - ), - ), - const SizedBox(height: 16), - const Text( - 'No hubs yet', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 8), - const Text( - 'Create clock-in stations for your locations', - textAlign: TextAlign.center, - style: TextStyle(color: Color(0xFF64748B), fontSize: 14), - ), - const SizedBox(height: 24), - ElevatedButton.icon( - onPressed: () => setState(() => _showAddHub = true), - icon: const Icon( - LucideIcons.plus, - size: 16, - color: Color(0xFF121826), - ), - label: const Text( - 'Add Your First Hub', - style: TextStyle( - color: Color(0xFF121826), - fontWeight: FontWeight.bold, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFFFED4A), - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - elevation: 4, - ), - ), - ], - ), - ); - } - - Widget _buildInfoCard() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), // blue-50 - borderRadius: BorderRadius.circular(16), - ), - child: const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(LucideIcons.nfc, size: 20, color: Color(0xFF2563EB)), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'About Hubs', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - SizedBox(height: 4), - Text( - 'Hubs are clock-in stations at your locations. Assign NFC tags to each hub so workers can quickly clock in/out using their phones.', - style: TextStyle( - color: Color(0xFF334155), - fontSize: 12, - height: 1.4, - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildAddHubDialog() { - return Container( - color: Colors.black.withOpacity(0.5), - child: Center( - child: Container( - width: MediaQuery.of(context).size.width * 0.9, - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 20), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Add New Hub', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 24), - _buildFieldLabel('Hub Name *'), - TextField( - controller: _nameController, - decoration: _buildInputDecoration( - 'e.g., Main Kitchen, Front Desk', - ), - ), - const SizedBox(height: 16), - _buildFieldLabel('Location Name'), - TextField( - controller: _locationNameController, - decoration: _buildInputDecoration('e.g., Downtown Restaurant'), - ), - const SizedBox(height: 16), - _buildFieldLabel('Address'), - TextField( - controller: _addressController, - decoration: _buildInputDecoration('Full address'), - ), - const SizedBox(height: 32), - Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () => setState(() => _showAddHub = false), - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - side: const BorderSide(color: Color(0xFFE2E8F0)), - ), - child: const Text( - 'Cancel', - style: TextStyle(color: Color(0xFF64748B)), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: ElevatedButton( - onPressed: _addHub, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFFFED4A), - foregroundColor: const Color(0xFF121826), - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: const Text( - 'Create Hub', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ], - ), - ), - ), - ); - } - - Widget _buildIdentifyNFCDialog() { - return Container( - color: Colors.black.withOpacity(0.5), - child: Center( - child: Container( - width: MediaQuery.of(context).size.width * 0.9, - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 20), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Identify NFC Tag', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 32), - Container( - width: 80, - height: 80, - decoration: const BoxDecoration( - color: Color(0xFFEFF6FF), // blue-50 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.nfc, - size: 40, - color: Color(0xFF2563EB), - ), - ), - const SizedBox(height: 16), - Text( - _selectedHub?['name'] ?? '', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 8), - const Text( - 'Tap your phone to the NFC tag to identify it', - textAlign: TextAlign.center, - style: TextStyle(color: Color(0xFF64748B), fontSize: 14), - ), - const SizedBox(height: 24), - ElevatedButton.icon( - onPressed: _simulateNFCScan, - icon: const Icon(LucideIcons.nfc, size: 20), - label: const Text( - 'Scan NFC Tag', - style: TextStyle(fontWeight: FontWeight.bold), - ), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric( - horizontal: 24, - vertical: 14, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - elevation: 4, - ), - ), - if (_nfcTagId != null) ...[ - const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFF0FDF4), // green-50 - borderRadius: BorderRadius.circular(16), - ), - child: Column( - children: [ - const Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - LucideIcons.checkCircle, - size: 20, - color: Color(0xFF16A34A), - ), - SizedBox(width: 8), - Text( - 'Tag Identified', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - ], - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFDCE8E0)), - ), - child: Text( - _nfcTagId!, - style: const TextStyle( - fontFamily: 'monospace', - fontWeight: FontWeight.bold, - fontSize: 12, - color: Color(0xFF334155), - ), - ), - ), - ], - ), - ), - ], - const SizedBox(height: 32), - Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () { - setState(() { - _showIdentifyNFC = false; - _nfcTagId = null; - _selectedHub = null; - }); - }, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - side: const BorderSide(color: Color(0xFFE2E8F0)), - ), - child: const Text( - 'Cancel', - style: TextStyle(color: Color(0xFF64748B)), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: ElevatedButton( - onPressed: _nfcTagId != null ? _assignTag : null, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFFFED4A), - foregroundColor: const Color(0xFF121826), - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: const Text( - 'Assign Tag', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ], - ), - ), - ), - ); - } - - Widget _buildFieldLabel(String label) { - return Padding( - padding: const EdgeInsets.only(bottom: 6), - child: Text( - label, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF0F172A), - ), - ), - ); - } - - InputDecoration _buildInputDecoration(String hint) { - return InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Color(0xFF94A3B8), fontSize: 14), - filled: true, - fillColor: const Color(0xFFF8FAFC), - contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: Color(0xFFE2E8F0)), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: Color(0xFFE2E8F0)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: Color(0xFF2563EB), width: 2), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_reports_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_reports_screen.dart deleted file mode 100644 index f983b22e..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_reports_screen.dart +++ /dev/null @@ -1,544 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class ClientReportsScreen extends StatefulWidget { - const ClientReportsScreen({super.key}); - - @override - State createState() => _ClientReportsScreenState(); -} - -class _ClientReportsScreenState extends State - with SingleTickerProviderStateMixin { - late TabController _tabController; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 4, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF0A39DF), // React primary - Color(0xFF0830B8), // React darker - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.go('/client-home'), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Workforce Control Tower', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - const SizedBox(height: 24), - // Tabs - Container( - height: 44, - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - ), - child: TabBar( - controller: _tabController, - indicator: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - labelColor: const Color(0xFF0A39DF), - unselectedLabelColor: Colors.white, - labelStyle: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - ), - indicatorSize: TabBarIndicatorSize.tab, - dividerColor: Colors.transparent, - tabs: const [ - Tab(text: 'Today'), - Tab(text: 'Week'), - Tab(text: 'Month'), - Tab(text: 'Quarter'), - ], - ), - ), - ], - ), - ), - - // Content - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Key Metrics - 6 items as in React - GridView.count( - crossAxisCount: 2, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.2, - children: const [ - _MetricCard( - icon: LucideIcons.clock, - label: 'Total Hrs', - value: '1,248', - badgeText: 'This period', - badgeColor: Color(0xFFEEF2FF), // indigo-50 - badgeTextColor: Color(0xFF4338CA), // indigo-700 - iconColor: Color(0xFF4F46E5), // indigo-600 - ), - _MetricCard( - icon: LucideIcons.trendingUp, - label: 'OT Hours', - value: '64', - badgeText: '5.1% of total', - badgeColor: Color(0xFFF1F5F9), // slate-100 - badgeTextColor: Color(0xFF475569), // slate-600 - iconColor: Color(0xFFD97706), // amber-600 - ), - _MetricCard( - icon: LucideIcons.dollarSign, - label: 'Total Spend', - value: '\$17.2k', - badgeText: '↓ 8% vs last week', - badgeColor: Color(0xFFD1FAE5), // emerald-100 - badgeTextColor: Color(0xFF047857), // emerald-700 - iconColor: Color(0xFF10B981), // emerald-600 - ), - _MetricCard( - icon: LucideIcons.trendingUp, - label: 'Fill Rate', - value: '96%', - badgeText: '↑ 2% improvement', - badgeColor: Color(0xFFDBEAFE), // blue-100 - badgeTextColor: Color(0xFF1D4ED8), // blue-700 - iconColor: Color(0xFF2563EB), // blue-600 - ), - _MetricCard( - icon: LucideIcons.clock, - label: 'Avg Fill Time', - value: '2.4 hrs', - badgeText: 'Industry best', - badgeColor: Color(0xFFDBEAFE), // blue-100 - badgeTextColor: Color(0xFF1D4ED8), // blue-700 - iconColor: Color(0xFF2563EB), // blue-600 - ), - _MetricCard( - icon: LucideIcons.alertTriangle, - label: 'No-Show Rate', - value: '2%', - badgeText: 'Below avg', - badgeColor: Color(0xFFD1FAE5), // emerald-100 - badgeTextColor: Color(0xFF047857), // emerald-700 - iconColor: Color(0xFFDC2626), // red-600 - ), - ], - ), - - // Quick Reports - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Quick Reports', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - TextButton.icon( - onPressed: () {}, - icon: const Icon(LucideIcons.download, size: 16), - label: const Text('Export All'), - style: TextButton.styleFrom( - foregroundColor: const Color(0xFF2563EB), // blue-600 - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - ), - ], - ), - - GridView.count( - crossAxisCount: 2, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.3, - children: const [ - _ReportCard( - icon: LucideIcons.calendar, - name: 'Daily Ops Report', - iconBgColor: Color(0xFFDBEAFE), // blue-100 - iconColor: Color(0xFF2563EB), // blue-600 - route: '/daily-ops-report', - ), - _ReportCard( - icon: LucideIcons.dollarSign, - name: 'Spend Report', - iconBgColor: Color(0xFFD1FAE5), // emerald-100 - iconColor: Color(0xFF059669), // emerald-600 - route: '/spend-report', - ), - _ReportCard( - icon: LucideIcons.users, - name: 'Coverage Report', - iconBgColor: Color(0xFFDBEAFE), // blue-100 - iconColor: Color(0xFF2563EB), // blue-600 - route: '/coverage-report-detail', - ), - _ReportCard( - icon: LucideIcons.alertTriangle, - name: 'No-Show Report', - iconBgColor: Color(0xFFFEE2E2), // red-100 - iconColor: Color(0xFFDC2626), // red-600 - route: '/no-show-report', - ), - _ReportCard( - icon: LucideIcons.trendingUp, - name: 'Forecast Report', - iconBgColor: Color(0xFFFEF3C7), // amber-100 - iconColor: Color(0xFFD97706), // amber-600 - route: '/forecast-report', - ), - _ReportCard( - icon: LucideIcons.barChart3, - name: 'Performance Report', - iconBgColor: Color(0xFFDBEAFE), // blue-100 - iconColor: Color(0xFF2563EB), // blue-600 - route: '/performance-report', - ), - ], - ), - - // AI Insights - Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFEBF5FF), // Light blue as in React - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 AI Insights', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 12), - _InsightRow( - children: [ - const TextSpan(text: 'You could save '), - const TextSpan( - text: '\$1,200/month', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const TextSpan( - text: ' by booking workers 48hrs in advance', - ), - ], - ), - _InsightRow( - children: [ - const TextSpan(text: 'Weekend demand is '), - const TextSpan( - text: '40% higher', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const TextSpan( - text: ' - consider scheduling earlier', - ), - ], - ), - _InsightRow( - children: [ - const TextSpan( - text: 'Your top 5 workers complete ', - ), - const TextSpan( - text: '95% of shifts', - style: TextStyle(fontWeight: FontWeight.bold), - ), - const TextSpan(text: ' - mark them as preferred'), - ], - ), - ], - ), - ), - - const SizedBox(height: 100), // pb-24 - ], - ), - ), - ], - ), - ), - ); - } -} - -class _MetricCard extends StatelessWidget { - final IconData icon; - final String label; - final String value; - final String badgeText; - final Color badgeColor; - final Color badgeTextColor; - final Color iconColor; - - const _MetricCard({ - required this.icon, - required this.label, - required this.value, - required this.badgeText, - required this.badgeColor, - required this.badgeTextColor, - required this.iconColor, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), // shadow-md - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Icon(icon, size: 16, color: iconColor), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - value, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: badgeColor, - borderRadius: BorderRadius.circular(10), - ), - child: Text( - badgeText, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: badgeTextColor, - ), - ), - ), - ], - ), - ], - ), - ); - } -} - -class _ReportCard extends StatelessWidget { - final IconData icon; - final String name; - final Color iconBgColor; - final Color iconColor; - final String route; - - const _ReportCard({ - required this.icon, - required this.name, - required this.iconBgColor, - required this.iconColor, - required this.route, - }); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () => context.push(route), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: iconBgColor, - borderRadius: BorderRadius.circular(12), - ), - child: Icon(icon, size: 20, color: iconColor), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - name, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - const Row( - children: [ - Icon( - LucideIcons.download, - size: 12, - color: Color(0xFF64748B), - ), - SizedBox(width: 4), - Text( - '2-click export', - style: TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - ], - ), - ], - ), - ], - ), - ), - ); - } -} - -class _InsightRow extends StatelessWidget { - final List children; - - const _InsightRow({required this.children}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '• ', - style: TextStyle(color: Color(0xFF334155), fontSize: 14), - ), - Expanded( - child: Text.rich( - TextSpan( - style: const TextStyle( - fontSize: 14, - color: Color(0xFF334155), - height: 1.4, - ), - children: children, - ), - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_settings_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_settings_screen.dart deleted file mode 100644 index d1a0ffa5..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_settings_screen.dart +++ /dev/null @@ -1,210 +0,0 @@ -import 'package:client_app_mvp/theme.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class ClientSettingsScreen extends StatelessWidget { - const ClientSettingsScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: CustomScrollView( - slivers: [ - SliverAppBar( - backgroundColor: AppColors.krowBlue, - expandedHeight: 200, - pinned: true, - flexibleSpace: FlexibleSpaceBar( - background: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [AppColors.krowBlue, Color(0xFF0047FF)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 40), - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: Colors.white24, width: 4), - color: Colors.white, - ), - child: Center( - child: Text( - 'C', - style: TextStyle( - fontSize: 32, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - ), - ), - const SizedBox(height: 12), - const Text( - 'Client', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - const SizedBox(height: 4), - const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.mail, size: 14, color: Colors.white70), - SizedBox(width: 6), - Text( - 'client@example.com', - style: TextStyle(color: Colors.white70, fontSize: 14), - ), - ], - ), - ], - ), - ), - ), - leading: IconButton( - icon: const Icon(LucideIcons.arrowLeft, color: Colors.white), - onPressed: () => context.pop(), - ), - title: const Text('Profile', style: TextStyle(color: Colors.white)), - ), - SliverPadding( - padding: const EdgeInsets.all(20), - sliver: SliverList( - delegate: SliverChildListDelegate([ - _buildActionButton( - 'Edit Profile', - () {}, - ), - const SizedBox(height: 16), - _buildActionButton( - 'Hubs', - () => context.push('/client-hubs'), - ), - const SizedBox(height: 16), - OutlinedButton( - onPressed: () => context.go('/client-sign-in'), - style: OutlinedButton.styleFrom( - minimumSize: const Size(double.infinity, 56), - side: const BorderSide(color: AppColors.krowCharcoal, width: 2), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - foregroundColor: AppColors.krowCharcoal, - ), - child: const Text( - 'Log Out', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - ), - const SizedBox(height: 24), - Card( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - side: BorderSide(color: Colors.grey.shade200), - ), - color: Colors.white, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Quick Links', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 12), - _buildQuickLink( - context, - icon: LucideIcons.nfc, - title: 'Clock-In Hubs', - onTap: () => context.push('/client-hubs'), - ), - _buildQuickLink( - context, - icon: LucideIcons.building2, - title: 'Billing & Payments', - onTap: () => context.push('/client-billing'), - ), - ], - ), - ), - ), - ]), - ), - ), - ], - ), - ); - } - - Widget _buildActionButton(String label, VoidCallback onTap) { - return ElevatedButton( - onPressed: onTap, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFFFFED4A), // krowYellow - foregroundColor: AppColors.krowCharcoal, - minimumSize: const Size(double.infinity, 56), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - elevation: 2, - ), - child: Text( - label, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - ); - } - - Widget _buildQuickLink( - BuildContext context, { - required IconData icon, - required String title, - required VoidCallback onTap, - }) { - return InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(8), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Icon(icon, size: 20, color: const Color(0xFF475569)), - const SizedBox(width: 12), - Text( - title, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const Icon(LucideIcons.chevronRight, size: 20, color: Color(0xFF94A3B8)), - ], - ), - ), - ); - } -} \ No newline at end of file diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_shifts_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_shifts_screen.dart deleted file mode 100644 index 4fb42e7e..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_shifts_screen.dart +++ /dev/null @@ -1,3161 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import 'package:url_launcher/url_launcher.dart'; - -// --- THEME CONSTANTS (Matching React) --- -class AppColors { - static const krowBlue = Color(0xFF0A39DF); - static const krowBlue50 = Color(0xFFEFF6FF); - static const krowBlue100 = Color(0xFFDBEAFE); - static const krowBlue600 = Color(0xFF2563EB); - static const krowBlue700 = Color(0xFF1D4ED8); - - static const krowSlate50 = Color(0xFFF8FAFC); - static const krowSlate100 = Color(0xFFF1F5F9); - static const krowSlate200 = Color(0xFFE2E8F0); - static const krowSlate300 = Color(0xFFCBD5E1); - static const krowSlate400 = Color(0xFF94A3B8); - static const krowSlate500 = Color(0xFF64748B); - static const krowSlate600 = Color(0xFF475569); - static const krowSlate700 = Color(0xFF334155); - static const krowSlate800 = Color(0xFF1E293B); - static const krowSlate900 = Color(0xFF0F172A); - - static const krowYellow = Color(0xFFF9E547); - static const krowCharcoal = Color(0xFF121826); - - static const krowAmber500 = Color(0xFFF59E0B); - static const krowAmber600 = Color(0xFFD97706); - static const krowAmber700 = Color(0xFFB45309); - - static const krowEmerald100 = Color(0xFFD1FAE5); - static const krowEmerald500 = Color(0xFF10B981); - static const krowEmerald600 = Color(0xFF059669); - static const krowEmerald700 = Color(0xFF047857); - - static const krowRed500 = Color(0xFFEF4444); - static const krowRed600 = Color(0xFFDC2626); -} - -class ClientShiftsScreen extends StatefulWidget { - const ClientShiftsScreen({super.key}); - - @override - State createState() => _ClientShiftsScreenState(); -} - -class _ClientShiftsScreenState extends State { - DateTime _selectedDate = DateTime.now(); - String _filterTab = 'all'; // 'all' (Up Next), 'active', 'completed' - int _weekOffset = 0; - - // Mock Data (Matching React Structure) - final List> _shifts = [ - { - 'id': '1', - 'title': 'Server - Wedding', - 'client_name': 'Grand Plaza Hotel', - 'status': 'filled', - 'date': DateTime.now() - .add(const Duration(days: 1)) - .toIso8601String() - .split('T')[0], - 'start_time': '16:00', - 'end_time': '23:00', - 'location': 'Grand Plaza Hotel, 123 Main St', - 'location_address': 'Grand Plaza Hotel, 123 Main St', - 'filled': 10, - 'workers_needed': 10, - 'hourly_rate': 22.0, - 'confirmed_apps': List.generate( - 10, - (index) => { - 'id': 'app_$index', - 'worker_id': 'w_$index', - 'worker_name': 'Worker ${String.fromCharCode(65 + index)}', - 'status': 'confirmed', - 'check_in_time': index < 5 ? '15:55' : null, - }, - ), - }, - { - 'id': '2', - 'title': 'Bartender - Private Event', - 'client_name': 'Taste of the Town', - 'status': 'open', - 'date': DateTime.now() - .add(const Duration(days: 1)) - .toIso8601String() - .split('T')[0], - 'start_time': '18:00', - 'end_time': '02:00', - 'location': 'Downtown Loft, 456 High St', - 'location_address': 'Downtown Loft, 456 High St', - 'filled': 4, - 'workers_needed': 5, - 'hourly_rate': 28.0, - 'confirmed_apps': List.generate( - 4, - (index) => { - 'id': 'app_b_$index', - 'worker_id': 'w_b_$index', - 'worker_name': 'Bartender ${index + 1}', - 'status': 'confirmed', - }, - ), - }, - { - 'id': '3', - 'title': 'Event Staff', - 'client_name': 'City Center', - 'status': 'in_progress', - 'date': DateTime.now().toIso8601String().split('T')[0], - 'start_time': '08:00', - 'end_time': '16:00', - 'location': 'Convention Center, 789 Blvd', - 'location_address': 'Convention Center, 789 Blvd', - 'filled': 15, - 'workers_needed': 15, - 'hourly_rate': 20.0, - 'confirmed_apps': List.generate( - 15, - (index) => { - 'id': 'app_c_$index', - 'worker_id': 'w_c_$index', - 'worker_name': 'Staff ${index + 1}', - 'status': 'confirmed', - 'check_in_time': '07:55', - }, - ), - }, - { - 'id': '4', - 'title': 'Coat Check', - 'client_name': 'The Met Museum', - 'status': 'completed', - 'date': DateTime.now() - .subtract(const Duration(days: 1)) - .toIso8601String() - .split('T')[0], - 'start_time': '17:00', - 'end_time': '22:00', - 'location': 'The Met Museum, 1000 5th Ave', - 'location_address': 'The Met Museum, 1000 5th Ave', - 'filled': 2, - 'workers_needed': 2, - 'hourly_rate': 18.0, - 'confirmed_apps': List.generate( - 2, - (index) => { - 'id': 'app_d_$index', - 'worker_id': 'w_d_$index', - 'worker_name': 'Checker ${index + 1}', - 'status': 'confirmed', - 'check_in_time': '16:50', - }, - ), - }, - ]; - - // Logic from React: Generate 7-day calendar window (Friday - Thursday) - List _getCalendarDays() { - final now = DateTime.now(); - // Dart weekday: 1=Mon ... 7=Sun - // JS getDay(): 0=Sun ... 6=Sat - // We need to map Dart weekday to JS-style for consistent math with the React code - // React logic: const currentDay = now.getDay(); // 0=Sun, 5=Fri - // daysSinceFriday = (currentDay + 2) % 7; - - int jsDay = now.weekday == 7 ? 0 : now.weekday; - int daysSinceFriday = (jsDay + 2) % 7; - - final startDate = DateTime(now.year, now.month, now.day) - .subtract(Duration(days: daysSinceFriday)) - .add(Duration(days: _weekOffset * 7)); - - return List.generate(7, (index) => startDate.add(Duration(days: index))); - } - - List> _getFilteredShifts() { - final selectedDateStr = _selectedDate.toIso8601String().split('T')[0]; - - // Filter by date - final shiftsOnDate = _shifts - .where((s) => s['date'] == selectedDateStr) - .toList(); - - // Sort by start time - shiftsOnDate.sort( - (a, b) => - (a['start_time'] as String).compareTo(b['start_time'] as String), - ); - - if (_filterTab == 'all') { - return shiftsOnDate - .where((s) => ['open', 'filled', 'confirmed'].contains(s['status'])) - .toList(); - } else if (_filterTab == 'active') { - return shiftsOnDate.where((s) => s['status'] == 'in_progress').toList(); - } else if (_filterTab == 'completed') { - return shiftsOnDate.where((s) => s['status'] == 'completed').toList(); - } - return []; - } - - int _getCategoryCount(String category) { - final selectedDateStr = _selectedDate.toIso8601String().split('T')[0]; - final shiftsOnDate = _shifts - .where((s) => s['date'] == selectedDateStr) - .toList(); - - if (category == 'active') { - return shiftsOnDate.where((s) => s['status'] == 'in_progress').length; - } else if (category == 'completed') { - return shiftsOnDate.where((s) => s['status'] == 'completed').length; - } - return 0; // Default for 'all' which is calculated differently in UI - } - - // Helper for Up Next Count - int _getUpNextCount() { - final selectedDateStr = _selectedDate.toIso8601String().split('T')[0]; - final shiftsOnDate = _shifts - .where((s) => s['date'] == selectedDateStr) - .toList(); - return shiftsOnDate - .where((s) => ['open', 'filled', 'confirmed'].contains(s['status'])) - .length; - } - - String _formatDateHeader(DateTime date) { - // Matches React formatDate logic roughly - final now = DateTime.now(); - final today = DateTime(now.year, now.month, now.day); - final tomorrow = today.add(const Duration(days: 1)); - final checkDate = DateTime(date.year, date.month, date.day); - - if (checkDate == today) return 'Today'; - if (checkDate == tomorrow) return 'Tomorrow'; - return DateFormat('EEE, MMM d').format(date); - } - - @override - Widget build(BuildContext context) { - final calendarDays = _getCalendarDays(); - final filteredShifts = _getFilteredShifts(); - - // Header Colors logic - String sectionTitle = ''; - Color dotColor = Colors.transparent; - - if (_filterTab == 'all') { - sectionTitle = 'Up Next'; - dotColor = AppColors.krowBlue600; - } else if (_filterTab == 'active') { - sectionTitle = 'Active'; - dotColor = AppColors.krowAmber600; - } else if (_filterTab == 'completed') { - sectionTitle = 'Completed'; - dotColor = AppColors.krowBlue; - } - - return Scaffold( - backgroundColor: Colors.white, // Fallback if gradient doesn't cover - body: Stack( - children: [ - // Background Gradient - Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [AppColors.krowSlate50, Colors.white], - stops: [0.0, 0.3], - ), - ), - ), - - SafeArea( - child: Column( - children: [ - // Header + Filter + Calendar (Sticky-ish behavior visual) - // React uses sticky top-0 bg-white/80 backdrop-blur-lg - ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.8), - border: Border( - bottom: BorderSide(color: AppColors.krowSlate100), - ), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Top Bar - Padding( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.go('/client-home'), - child: Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: AppColors.krowSlate100, - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.arrowLeft, - color: AppColors.krowSlate600, - size: 20, - ), - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Orders', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - ), - ), - ], - ), - ElevatedButton( - onPressed: () => - context.push('/create-order'), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 10, - ), - ), - child: const Row( - children: [ - Icon(LucideIcons.plus, size: 16), - SizedBox(width: 4), - Text( - 'Post', - style: TextStyle( - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ], - ), - ), - - // Filter Tabs - Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - _buildFilterTab('Up Next', null, 'all'), - const SizedBox(width: 24), - _buildFilterTab( - 'Active', - _getCategoryCount('active') + - _getUpNextCount(), - 'active', - showCount: true, - ), - const SizedBox(width: 24), - _buildFilterTab( - 'Completed', - _getCategoryCount('completed'), - 'completed', - showCount: true, - ), - ], - ), - ), - - // Calendar Header controls - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 8, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: const Icon( - LucideIcons.chevronLeft, - size: 20, - color: AppColors.krowSlate600, - ), - onPressed: () => - setState(() => _weekOffset--), - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - splashRadius: 20, - ), - Text( - DateFormat( - 'MMMM yyyy', - ).format(calendarDays.first), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowSlate600, - ), - ), - IconButton( - icon: const Icon( - LucideIcons.chevronRight, - size: 20, - color: AppColors.krowSlate600, - ), - onPressed: () => - setState(() => _weekOffset++), - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - splashRadius: 20, - ), - ], - ), - ), - - // Calendar Grid - SizedBox( - height: 72, - child: ListView.separated( - padding: const EdgeInsets.symmetric( - horizontal: 20, - ), - scrollDirection: Axis.horizontal, - itemCount: 7, - separatorBuilder: (context, index) => - const SizedBox(width: 8), - itemBuilder: (context, index) { - final date = calendarDays[index]; - final isSelected = - date.year == _selectedDate.year && - date.month == _selectedDate.month && - date.day == _selectedDate.day; - - // Check if this date has any shifts (any status) - final dateStr = date.toIso8601String().split( - 'T', - )[0]; - final hasShifts = _shifts.any( - (s) => s['date'] == dateStr, - ); - - return GestureDetector( - onTap: () => - setState(() => _selectedDate = date), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - width: 48, - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue - : Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: isSelected - ? AppColors.krowBlue - : AppColors.krowSlate200, - ), - boxShadow: isSelected - ? [ - BoxShadow( - color: AppColors.krowBlue - .withValues(alpha: 0.25), - blurRadius: 12, - offset: const Offset(0, 4), - ), - ] - : null, - ), - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Text( - DateFormat('dd').format(date), - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : AppColors.krowSlate900, - ), - ), - Text( - DateFormat('E').format(date), - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: isSelected - ? Colors.white.withValues( - alpha: 0.8, - ) - : AppColors.krowSlate500, - ), - ), - if (hasShifts) ...[ - const SizedBox(height: 4), - Container( - width: 6, - height: 6, - decoration: BoxDecoration( - color: isSelected - ? Colors.white - : AppColors.krowBlue, - shape: BoxShape.circle, - ), - ), - ], - ], - ), - ), - ); - }, - ), - ), - const SizedBox( - height: 16, - ), // Padding bottom of header - ], - ), - ), - ), - ), - - // Content List - Expanded( - child: filteredShifts.isEmpty - ? _buildEmptyState() - : ListView( - padding: const EdgeInsets.fromLTRB(20, 16, 20, 100), - children: [ - if (filteredShifts.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - children: [ - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: dotColor, - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - Text( - sectionTitle.toUpperCase(), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - letterSpacing: 0.5, - ), - ), - const SizedBox(width: 4), - Text( - '(${filteredShifts.length})', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate400, - ), - ), - ], - ), - ), - ...filteredShifts.map( - (shift) => Padding( - padding: const EdgeInsets.only(bottom: 12), - child: _OrderCoverageCard(shift: shift), - ), - ), - ], - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildFilterTab( - String label, - int? count, - String tabId, { - bool showCount = false, - }) { - final isSelected = _filterTab == tabId; - - // Logic to handle count display for Active tab per React code - // React: Active ({comingUpShifts.length + inProgressShifts.length}) - // For Flutter, just pass the calculated count. - - String text = label; - if (showCount && count != null) { - text = '$label ($count)'; - } - - return GestureDetector( - onTap: () => setState(() => _filterTab = tabId), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Text( - text, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: isSelected ? AppColors.krowBlue : AppColors.krowSlate400, - ), - ), - ), - AnimatedContainer( - duration: const Duration(milliseconds: 200), - height: 2, - width: isSelected ? 40 : 0, // Animate width - decoration: BoxDecoration( - color: AppColors.krowBlue, - borderRadius: BorderRadius.circular(2), - ), - ), - if (!isSelected) const SizedBox(height: 2), // Placeholder for height - ], - ), - ); - } - - Widget _buildEmptyState() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - LucideIcons.calendar, - size: 48, - color: AppColors.krowSlate300, - ), - const SizedBox(height: 12), - Text( - 'No orders for ${_formatDateHeader(_selectedDate)}', - style: const TextStyle(color: AppColors.krowSlate500), - ), - const SizedBox(height: 16), - ElevatedButton( - onPressed: () => context.push('/create-order'), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), - ), - child: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(LucideIcons.plus, size: 16), - SizedBox(width: 8), - Text('Post an Order'), - ], - ), - ), - ], - ), - ); - } -} - -class _OrderCoverageCard extends StatefulWidget { - final Map shift; - - const _OrderCoverageCard({required this.shift}); - - @override - State<_OrderCoverageCard> createState() => _OrderCoverageCardState(); -} - -class _OrderCoverageCardState extends State<_OrderCoverageCard> { - bool _expanded = true; // Default expanded in React is true - - void _openEditSheet(Map shiftData) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) { - return _UnifiedOrderFlowSheet( - initialOrder: shiftData, - onBack: () { - Navigator.pop(context); // Close the sheet - // Invalidate queries or refresh data if needed - }, - ); - }, - ); - } - - // Helpers - Color _getStatusColor(String status) { - switch (status) { - case 'filled': - case 'confirmed': - return AppColors.krowBlue; - case 'completed': - return AppColors.krowBlue; - case 'in_progress': - return AppColors.krowAmber600; - case 'cancelled': - return AppColors.krowRed500; - default: - return AppColors.krowAmber600; // Open/Default - } - } - - String _getStatusLabel(String status) { - switch (status) { - case 'filled': - case 'confirmed': - return 'CONFIRMED'; - case 'in_progress': - return 'ACTIVE'; - default: - return status.toUpperCase(); - } - } - - String _formatTime(String time) { - if (time.isEmpty) return ''; - final parts = time.split(':'); - int hour = int.parse(parts[0]); - int minute = int.parse(parts[1]); - String ampm = hour >= 12 ? 'PM' : 'AM'; - hour = hour % 12; - if (hour == 0) hour = 12; - return '$hour:${minute.toString().padLeft(2, '0')} $ampm'; - } - - String _formatDate(String dateStr) { - final date = DateTime.parse(dateStr); - // Use helper from main screen or simple local - final now = DateTime.now(); - final today = DateTime(now.year, now.month, now.day); - final tomorrow = today.add(const Duration(days: 1)); - final checkDate = DateTime(date.year, date.month, date.day); - - if (checkDate == today) return 'Today'; - if (checkDate == tomorrow) return 'Tomorrow'; - return DateFormat('EEE, MMM d').format(date); - } - - void _showSnackbar(String message) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(message), duration: const Duration(seconds: 2)), - ); - } - - void _showMessageAllSheet() { - final TextEditingController _messageController = TextEditingController(); - final List workers = - widget.shift['confirmed_apps'] ?? []; // Get worker list from shift - final String shiftTitle = widget.shift['title'] ?? 'Shift'; - - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) { - return Container( - height: MediaQuery.of(context).size.height * 0.8, // Adjust height - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Column( - children: [ - // Header - Padding( - padding: const EdgeInsets.all(20), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Message All Workers for $shiftTitle', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - IconButton( - icon: const Icon(LucideIcons.x), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ), - const Divider(height: 1), - // Recipients - Expanded( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Recipients:', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 8), - Wrap( - spacing: 8, - runSpacing: 8, - children: workers.map((worker) { - return Chip( - label: Text(worker['worker_name']), - backgroundColor: AppColors.krowBlue50, - labelStyle: const TextStyle( - color: AppColors.krowBlue700, - fontSize: 12, - ), - ); - }).toList(), - ), - const SizedBox(height: 20), - // Message Input - const Text( - 'Your Message:', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 8), - TextField( - controller: _messageController, - maxLines: 5, - decoration: InputDecoration( - hintText: 'Type your message here...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowSlate200, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBlue, - ), - ), - ), - ), - ], - ), - ), - ), - // Send Button - Padding( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 100), - child: SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Message "${_messageController.text}" sent to ${workers.length} workers (Placeholder)', - ), - duration: const Duration(seconds: 2), - ), - ); - Navigator.pop(context); // Close the sheet - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - 'Send Message', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - ); - }, - ); - } - - Future _launchPhoneCall(String phoneNumber) async { - final Uri launchUri = Uri(scheme: 'tel', path: phoneNumber); - await launchUrl(launchUri); - } - - void _showWorkerChatSheet(String workerName) { - final TextEditingController _chatMessageController = - TextEditingController(); - // Mock chat history - final List> mockChatHistory = [ - { - 'sender': workerName, - 'message': 'Hi, I\'m running a bit late, maybe 10 mins.', - 'time': '10:05 AM', - }, - { - 'sender': 'You', - 'message': 'Okay, thanks for the heads up! Drive safely.', - 'time': '10:07 AM', - }, - { - 'sender': workerName, - 'message': 'Will do! Almost there.', - 'time': '10:20 AM', - }, - ]; - - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) { - return Container( - height: MediaQuery.of(context).size.height * 0.8, // Adjust height - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: SafeArea( - child: Column( - children: [ - // Header - Padding( - padding: const EdgeInsets.all(20), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Chat with $workerName', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - IconButton( - icon: const Icon(LucideIcons.x), - onPressed: () => Navigator.pop(context), - ), - ], - ), - ), - const Divider(height: 1), - // Chat History - Expanded( - child: ListView.builder( - padding: const EdgeInsets.all(20), - reverse: true, // Show latest messages at the bottom - itemCount: mockChatHistory.length, - itemBuilder: (context, index) { - final message = - mockChatHistory[mockChatHistory.length - - 1 - - index]; // Reverse order for display - final isMe = message['sender'] == 'You'; - return Align( - alignment: isMe - ? Alignment.centerRight - : Alignment.centerLeft, - child: Container( - margin: const EdgeInsets.only(bottom: 10), - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: isMe - ? AppColors.krowBlue - : AppColors.krowSlate100, - borderRadius: BorderRadius.circular(12), - ), - child: Column( - crossAxisAlignment: isMe - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - Text( - message['message']!, - style: TextStyle( - color: isMe - ? Colors.white - : AppColors.krowSlate900, - ), - ), - const SizedBox(height: 4), - Text( - '${message['sender']} - ${message['time']}', - style: TextStyle( - color: isMe - ? Colors.white70 - : AppColors.krowSlate400, - fontSize: 10, - ), - ), - ], - ), - ), - ); - }, - ), - ), - // Message Input - Padding( - padding: const EdgeInsets.all(20), - child: Row( - children: [ - Expanded( - child: TextField( - controller: _chatMessageController, - decoration: InputDecoration( - hintText: 'Type a message...', - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(24), - borderSide: BorderSide.none, - ), - filled: true, - fillColor: AppColors.krowSlate100, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - ), - ), - ), - ), - const SizedBox(width: 12), - CircleAvatar( - backgroundColor: AppColors.krowBlue, - radius: 24, - child: IconButton( - icon: const Icon( - LucideIcons.send, - color: Colors.white, - ), - onPressed: () { - if (_chatMessageController.text.isNotEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Message "${_chatMessageController.text}" sent to $workerName (Placeholder)', - ), - duration: const Duration(seconds: 2), - ), - ); - _chatMessageController.clear(); - // In a real app, add message to history and update UI - } - }, - ), - ), - ], - ), - ), - ], - ), - ), - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - final shift = widget.shift; - final statusColor = _getStatusColor(shift['status']); - final statusLabel = _getStatusLabel(shift['status']); - final filled = shift['filled'] as int; - final needed = shift['workers_needed'] as int; - final coveragePercent = needed > 0 ? ((filled / needed) * 100).round() : 0; - - // Calculations - final confirmedApps = shift['confirmed_apps'] as List; - final cost = - (shift['hourly_rate'] as double) * 8 * (filled > 0 ? filled : needed); - // React calculates hours based on start/end, default 8. Mock: - double hours = 8.0; - - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: AppColors.krowBlue.withValues(alpha: 0.12), // #0A39DF20 - width: 1.5, - ), - boxShadow: [ - BoxShadow( - color: AppColors.krowBlue.withValues(alpha: 0.08), - blurRadius: 3, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header Row - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Status Dot & Label - Row( - children: [ - Container( - width: 6, - height: 6, - decoration: BoxDecoration( - color: statusColor, - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - Text( - statusLabel, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: statusColor, - letterSpacing: 0.5, - ), - ), - ], - ), - const SizedBox(height: 2), - // Title - Text( - shift['title'], - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - ), - ), - const SizedBox(height: 4), - // Client & Date - Row( - children: [ - Text( - shift['client_name'], - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate500, - ), - ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 4), - child: Text( - '•', - style: TextStyle( - color: AppColors.krowSlate400, - ), - ), - ), - Text( - _formatDate(shift['date']), - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowSlate600, - ), - ), - ], - ), - const SizedBox(height: 4), - // Address - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: AppColors.krowSlate600, - ), - const SizedBox(width: 4), - Expanded( - child: Text( - shift['location_address'], - style: const TextStyle( - fontSize: 11, - color: AppColors.krowSlate600, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - const SizedBox(width: 4), - GestureDetector( - onTap: () { - _showSnackbar(shift['location_address']); - }, - child: const Row( - children: [ - Icon( - LucideIcons.navigation, - size: 12, - color: AppColors.krowBlue600, - ), - SizedBox(width: 2), - Text( - 'Get direction', - style: TextStyle( - fontSize: 11, - color: AppColors.krowBlue600, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ], - ), - ], - ), - ), - // Actions (Edit & Expand) - Row( - children: [ - _buildHeaderIconButton( - icon: LucideIcons.edit2, - color: AppColors.krowBlue600, - bgColor: AppColors.krowBlue50, - onTap: () => _openEditSheet(shift), - ), - const SizedBox(width: 8), - _buildHeaderIconButton( - icon: _expanded - ? LucideIcons.chevronUp - : LucideIcons.chevronDown, - color: AppColors.krowSlate600, - bgColor: AppColors.krowSlate50, - onTap: () => setState(() => _expanded = !_expanded), - ), - ], - ), - ], - ), - - const SizedBox(height: 12), - const Divider(height: 1, color: AppColors.krowSlate100), - const SizedBox(height: 12), - - // Stats Row - Row( - children: [ - Expanded( - child: _buildStatItem( - icon: LucideIcons.dollarSign, - value: '\$${cost.round()}', - label: 'Total', - ), - ), - Container( - width: 1, - height: 32, - color: AppColors.krowSlate100, - ), - Expanded( - child: _buildStatItem( - icon: LucideIcons.clock, - value: hours.toStringAsFixed(1), - label: 'HRS', - ), - ), - Container( - width: 1, - height: 32, - color: AppColors.krowSlate100, - ), - Expanded( - child: _buildStatItem( - icon: LucideIcons.users, - value: '${filled > 0 ? filled : needed}', - label: 'workers', - ), - ), - ], - ), - - const SizedBox(height: 16), - - // Clock In/Out Boxes - Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: AppColors.krowSlate50, - borderRadius: BorderRadius.circular(8), - ), - child: Column( - children: [ - const Text( - 'CLOCK IN', - style: TextStyle( - fontSize: 9, - color: AppColors.krowSlate500, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 2), - Text( - _formatTime(shift['start_time']), - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowSlate900, - ), - ), - ], - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: AppColors.krowSlate50, - borderRadius: BorderRadius.circular(8), - ), - child: Column( - children: [ - const Text( - 'CLOCK OUT', - style: TextStyle( - fontSize: 9, - color: AppColors.krowSlate500, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 2), - Text( - _formatTime(shift['end_time']), - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowSlate900, - ), - ), - ], - ), - ), - ), - ], - ), - - const SizedBox(height: 12), - - // Coverage Status - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Icon( - LucideIcons.checkCircle, - size: 16, - color: AppColors.krowEmerald500, - ), - const SizedBox(width: 6), - Text( - '$filled/$needed Workers', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowSlate900, - ), - ), - ], - ), - Text( - '$coveragePercent%', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue600, - ), - ), - ], - ), - const SizedBox(height: 8), - // Coverage Bar - Stack( - children: [ - Container( - height: 8, - width: double.infinity, - decoration: BoxDecoration( - color: AppColors.krowSlate100, - borderRadius: BorderRadius.circular(4), - ), - ), - AnimatedContainer( - duration: const Duration(milliseconds: 300), - height: 8, - width: - MediaQuery.of(context).size.width * - (coveragePercent / 100) * - 0.8, // Approximation - decoration: BoxDecoration( - color: AppColors.krowBlue600, - borderRadius: BorderRadius.circular(4), - ), - ), - ], - ), - - // Avatars Stack (Preview) - if (confirmedApps.isNotEmpty) ...[ - const SizedBox(height: 12), - Row( - children: [ - SizedBox( - height: 28, - width: - 28.0 + - (confirmedApps.length > 3 - ? 3 - : confirmedApps.length - 1) * - 20.0, - child: Stack( - children: [ - for ( - int i = 0; - i < - (confirmedApps.length > 3 - ? 3 - : confirmedApps.length); - i++ - ) - Positioned( - left: i * 20.0, - child: Container( - width: 28, - height: 28, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: Colors.white, - width: 2, - ), - color: AppColors.krowBlue100, - ), - child: Center( - child: Text( - (confirmedApps[i]['worker_name'] - as String)[0], - style: const TextStyle( - fontSize: 10, - color: AppColors.krowBlue700, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - ), - if (confirmedApps.length > 3) - Padding( - padding: const EdgeInsets.only(left: 8), - child: Text( - '+${confirmedApps.length - 3} more', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate500, - ), - ), - ), - ], - ), - ], - ], - ), - ), - - // Expanded Content - if (_expanded && confirmedApps.isNotEmpty) - Container( - decoration: const BoxDecoration( - color: AppColors.krowSlate50, - border: Border(top: BorderSide(color: AppColors.krowSlate100)), - borderRadius: BorderRadius.vertical( - bottom: Radius.circular(12), - ), - ), - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Assigned Workers', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowSlate700, - ), - ), - SizedBox( - height: 28, - child: ElevatedButton.icon( - onPressed: _showMessageAllSheet, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue600, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(horizontal: 10), - elevation: 0, - textStyle: const TextStyle(fontSize: 10), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), - ), - ), - icon: const Icon(LucideIcons.messageCircle, size: 12), - label: const Text('Message All'), - ), - ), - ], - ), - const SizedBox(height: 12), - - // Worker List - ...confirmedApps.take(5).map((app) => _buildWorkerRow(app)), - - if (confirmedApps.length > 5) - Padding( - padding: const EdgeInsets.only(top: 8), - child: Center( - child: TextButton( - onPressed: () => - setState(() => _expanded = !_expanded), - child: Text( - 'Show ${confirmedApps.length - 5} more workers', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowBlue600, - ), - ), - ), - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildWorkerRow(Map app) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - // Avatar - Container( - width: 36, - height: 36, - decoration: const BoxDecoration( - color: AppColors.krowBlue50, - shape: BoxShape.circle, - ), - child: Center( - child: Text( - (app['worker_name'] as String)[0], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue700, - ), - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - app['worker_name'], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowSlate900, - ), - ), - const SizedBox(height: 2), - Row( - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 1, - ), - decoration: BoxDecoration( - border: Border.all(color: AppColors.krowSlate200), - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - '⭐ 4.8', - style: TextStyle( - fontSize: 10, - color: AppColors.krowSlate500, - ), - ), - ), - if (app['check_in_time'] != null) ...[ - const SizedBox(width: 4), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 1, - ), - decoration: BoxDecoration( - color: AppColors.krowEmerald100, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'Checked In', - style: TextStyle( - fontSize: 10, - color: AppColors.krowEmerald700, - ), - ), - ), - ], - ], - ), - ], - ), - ], - ), - - // Actions - Row( - children: [ - _buildActionIcon( - LucideIcons.phone, - AppColors.krowBlue600, - () => _launchPhoneCall( - 'tel:+1-555-123-4567', - ), // Placeholder number - ), - const SizedBox(width: 8), - _buildActionIcon( - LucideIcons.messageCircle, - AppColors.krowBlue600, - () => _showWorkerChatSheet(app['worker_name']), - ), - const SizedBox(width: 8), - const Icon( - LucideIcons.checkCircle, - size: 20, - color: AppColors.krowEmerald500, - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildActionIcon(IconData icon, Color color, VoidCallback onTap) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 32, - height: 32, - decoration: const BoxDecoration( - color: Colors.transparent, // Ghost button equivalent - ), - child: Icon(icon, size: 16, color: color), - ), - ); - } - - Widget _buildStatItem({ - required IconData icon, - required String value, - required String label, - }) { - return Column( - children: [ - Icon(icon, size: 14, color: AppColors.krowSlate400), - const SizedBox(height: 4), - Text( - value, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - ), - ), - Text( - label, - style: const TextStyle(fontSize: 9, color: AppColors.krowSlate500), - ), - ], - ); - } - - Widget _buildHeaderIconButton({ - required IconData icon, - required Color color, - required Color bgColor, - required VoidCallback onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: bgColor, - borderRadius: BorderRadius.circular(8), - ), - child: Icon(icon, size: 16, color: color), - ), - ); - } -} - -// Constants -const Map _roleRates = { - 'Server': 18.0, - 'Bartender': 22.0, - 'Cook': 20.0, - 'Busser': 16.0, - 'Host': 17.0, - 'Barista': 16.0, - 'Dishwasher': 15.0, - 'Event Staff': 20.0, - 'Manager': 25.0, -}; - -const List _roles = [ - 'Server', - 'Bartender', - 'Cook', - 'Busser', - 'Host', - 'Barista', - 'Dishwasher', - 'Event Staff', - 'Manager', -]; - -class _UnifiedOrderFlowSheet extends StatefulWidget { - final Map initialOrder; - final VoidCallback onBack; - - const _UnifiedOrderFlowSheet({ - required this.initialOrder, - required this.onBack, - }); - - @override - State<_UnifiedOrderFlowSheet> createState() => _UnifiedOrderFlowSheetState(); -} - -class _UnifiedOrderFlowSheetState extends State<_UnifiedOrderFlowSheet> { - late TextEditingController _dateController; - late TextEditingController _globalLocationController; - - // Order state - List> _positions = []; - bool _showReview = false; - bool _submitted = false; - bool _isLoading = false; - - // Validation errors - Map _errors = {}; - - @override - void initState() { - super.initState(); - final order = widget.initialOrder; - - _dateController = TextEditingController(text: order['date'] ?? ''); - _globalLocationController = TextEditingController( - text: order['location_address'] ?? order['location'] ?? '', - ); - - // Initialize positions - // In edit mode (from card), we usually have 1 position derived from the shift. - // If we want to support multiple, we'd need a different data structure or assume 1 for edit. - - final initialRole = _getInitialRole(order['title'] ?? ''); - - _positions = [ - { - 'role': initialRole, - 'count': order['workers_needed'] ?? 1, - 'start_time': order['start_time'] ?? '', - 'end_time': order['end_time'] ?? '', - 'location': '', // Override location - 'lunch_break': 30, - 'show_location_override': false, - }, - ]; - } - - String _getInitialRole(String title) { - if (_roles.contains(title)) return title; - - // Check if title contains any role - for (final role in _roles) { - if (title.contains(role)) { - return role; - } - } - - return ''; // Default to empty if no match found - } - - @override - void dispose() { - _dateController.dispose(); - _globalLocationController.dispose(); - super.dispose(); - } - - void _addPosition() { - setState(() { - _positions.add({ - 'role': '', - 'count': 1, - 'start_time': '', - 'end_time': '', - 'location': '', - 'lunch_break': 30, - 'show_location_override': false, - }); - }); - } - - void _removePosition(int index) { - if (_positions.length > 1) { - setState(() { - _positions.removeAt(index); - }); - } - } - - void _updatePosition(int index, String key, dynamic value) { - setState(() { - _positions[index][key] = value; - // Clear error for this field if exists - if (_errors.containsKey('${key}_$index')) { - _errors.remove('${key}_$index'); - } - }); - } - - bool _validate() { - final newErrors = {}; - - if (_dateController.text.isEmpty) { - newErrors['date'] = 'Date is required'; - } - - if (_globalLocationController.text.isEmpty) { - // Check if all positions have overrides - bool allHaveLocation = _positions.every( - (p) => - p['show_location_override'] == true && - p['location'].toString().isNotEmpty, - ); - if (!allHaveLocation) { - newErrors['location'] = 'Location is required'; - } - } - - for (int i = 0; i < _positions.length; i++) { - final pos = _positions[i]; - if (pos['role'].toString().isEmpty) newErrors['role_$i'] = 'Required'; - if (pos['start_time'].toString().isEmpty) - newErrors['start_time_$i'] = 'Required'; - if (pos['end_time'].toString().isEmpty) - newErrors['end_time_$i'] = 'Required'; - - if (pos['show_location_override'] == true && - pos['location'].toString().isEmpty) { - newErrors['location_$i'] = 'Required'; - } - } - - setState(() { - _errors = newErrors; - }); - return newErrors.isEmpty; - } - - void _submit() async { - setState(() => _isLoading = true); - // Simulate network delay - await Future.delayed(const Duration(seconds: 1)); - if (mounted) { - setState(() { - _isLoading = false; - _submitted = true; - }); - } - } - - double _calculateTotalCost() { - double total = 0; - for (var pos in _positions) { - final role = pos['role'] ?? ''; - final rate = _roleRates[role] ?? 0.0; - final count = pos['count'] as int; - // Estimate hours (simple parsing) - double hours = 8.0; - if (pos['start_time'] != '' && pos['end_time'] != '') { - try { - // Simple calc, ignore date crossing for MVP - final startParts = pos['start_time'].toString().split(':'); - final endParts = pos['end_time'].toString().split(':'); - final startH = - int.parse(startParts[0]) + int.parse(startParts[1]) / 60; - final endH = int.parse(endParts[0]) + int.parse(endParts[1]) / 60; - - hours = endH - startH; - if (hours < 0) hours += 24; // Crossed midnight - } catch (_) {} - } - - total += rate * hours * count; - } - return total; - } - - @override - Widget build(BuildContext context) { - if (_submitted) { - return _buildSuccessView(); - } - - if (_showReview) { - return _buildReviewView(); - } - - return _buildFormView(); - } - - Widget _buildFormView() { - return Container( - height: MediaQuery.of(context).size.height * 0.95, - decoration: const BoxDecoration( - color: AppColors.krowSlate50, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 16), - decoration: const BoxDecoration( - color: AppColors.krowBlue, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Row( - children: [ - GestureDetector( - onTap: widget.onBack, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.2), - borderRadius: BorderRadius.circular(12), - ), - child: const Center( - child: Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 24, - ), - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Edit Order', // Or "Create Order" dynamic - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Fast & flexible staffing', - style: TextStyle(fontSize: 12, color: Colors.white70), - ), - ], - ), - ], - ), - ), - - // Content - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - // Global Fields - _buildSectionLabel('Date *'), - _buildDatePicker( - controller: _dateController, - error: _errors['date'], - ), - const SizedBox(height: 16), - - _buildSectionLabel('Location *'), - _buildTextField( - controller: _globalLocationController, - hint: 'Business address', - icon: LucideIcons.mapPin, - error: _errors['location'], - ), - const SizedBox(height: 24), - - // Positions Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Positions', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - ), - ), - TextButton.icon( - onPressed: _addPosition, - icon: const Icon(LucideIcons.plus, size: 16), - label: const Text('Add Position'), - style: TextButton.styleFrom( - foregroundColor: AppColors.krowBlue600, - textStyle: const TextStyle( - fontWeight: FontWeight.w600, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - - // Position Cards - ..._positions.asMap().entries.map((entry) { - final index = entry.key; - final pos = entry.value; - return _buildPositionCard(index, pos); - }), - - const SizedBox(height: 80), // Bottom padding - ], - ), - ), - ), - - // Footer - Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowSlate200)), - ), - child: SafeArea( - top: false, - child: ElevatedButton( - onPressed: () { - if (_validate()) { - setState(() => _showReview = true); - } - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - minimumSize: const Size(double.infinity, 48), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: Text( - 'Review ${_positions.length} Position${_positions.length > 1 ? 's' : ''}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - ); - } - - Widget _buildReviewView() { - final totalWorkers = _positions.fold( - 0, - (sum, p) => sum + (p['count'] as int), - ); - final totalCost = _calculateTotalCost(); - - return Container( - height: MediaQuery.of(context).size.height * 0.95, - decoration: const BoxDecoration( - color: AppColors.krowSlate50, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 16), - decoration: const BoxDecoration( - color: AppColors.krowBlue, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Row( - children: [ - GestureDetector( - onTap: () => setState(() => _showReview = false), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.2), - borderRadius: BorderRadius.circular(12), - ), - child: const Center( - child: Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 24, - ), - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Review Order', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Confirm details before posting', - style: TextStyle(fontSize: 12, color: Colors.white70), - ), - ], - ), - ], - ), - ), - - // Content - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Summary Card - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - AppColors.krowBlue50, - Color(0xFFDBEAFE), - ], // blue-50 to blue-100 - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: AppColors.krowBlue.withValues(alpha: 0.2), - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - _buildSummaryItem('${_positions.length}', 'Positions'), - _buildSummaryItem('$totalWorkers', 'Workers'), - _buildSummaryItem( - '\$${totalCost.round()}', - 'Est. Cost', - ), - ], - ), - ), - const SizedBox(height: 20), - - // Order Details - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowSlate200), - ), - child: Column( - children: [ - Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 16, - color: AppColors.krowBlue600, - ), - const SizedBox(width: 8), - Text( - _dateController.text, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: AppColors.krowSlate900, - ), - ), - ], - ), - if (_globalLocationController.text.isNotEmpty) ...[ - const SizedBox(height: 12), - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 16, - color: AppColors.krowBlue600, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - _globalLocationController.text, - style: const TextStyle( - color: AppColors.krowSlate900, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ], - ], - ), - ), - const SizedBox(height: 24), - - const Text( - 'Positions Breakdown', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - ), - ), - const SizedBox(height: 12), - - ..._positions.map((pos) { - final role = pos['role'] ?? 'Unknown'; - final rate = _roleRates[role] ?? 0.0; - - double hours = 0; - if (pos['start_time'] != '' && pos['end_time'] != '') { - try { - final startParts = pos['start_time'].toString().split( - ':', - ); - final endParts = pos['end_time'].toString().split(':'); - final startH = - int.parse(startParts[0]) + - int.parse(startParts[1]) / 60; - final endH = - int.parse(endParts[0]) + - int.parse(endParts[1]) / 60; - - hours = endH - startH; - if (hours < 0) hours += 24; - } catch (_) {} - } - - final cost = hours * rate * (pos['count'] as int); - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowSlate100), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - role, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: AppColors.krowSlate900, - ), - ), - Text( - '${pos['count']} worker${pos['count'] > 1 ? 's' : ''}', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate500, - ), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '\$${cost.round()}', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - Text( - '\$${rate.toStringAsFixed(0)}/hr', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate500, - ), - ), - ], - ), - ], - ), - const SizedBox(height: 12), - Row( - children: [ - const Icon( - LucideIcons.clock, - size: 14, - color: AppColors.krowSlate400, - ), - const SizedBox(width: 6), - Text( - '${pos['start_time']} - ${pos['end_time']}', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate600, - ), - ), - if (pos['location'].toString().isNotEmpty) ...[ - const SizedBox(width: 16), - const Icon( - LucideIcons.mapPin, - size: 14, - color: AppColors.krowSlate400, - ), - const SizedBox(width: 6), - Expanded( - child: Text( - pos['location'], - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate600, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ], - ), - ], - ), - ); - }), - - const SizedBox(height: 80), - ], - ), - ), - ), - - // Footer - Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowSlate200)), - ), - child: SafeArea( - top: false, - child: Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () => setState(() => _showReview = false), - style: OutlinedButton.styleFrom( - foregroundColor: AppColors.krowSlate900, - side: const BorderSide(color: AppColors.krowSlate300), - minimumSize: const Size(double.infinity, 48), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text('Edit'), - ), - ), - const SizedBox(width: 12), - Expanded( - child: ElevatedButton( - onPressed: _isLoading ? null : _submit, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - minimumSize: const Size(double.infinity, 48), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: _isLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) - : const Text( - 'Confirm & Post', - style: TextStyle(fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildSuccessView() { - return Container( - width: double.infinity, - height: MediaQuery.of(context).size.height * 0.95, - decoration: const BoxDecoration( - color: AppColors.krowBlue, // Primary background - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 80, - height: 80, - decoration: const BoxDecoration( - color: Color(0xFFF9E547), // krowYellow (Accent) - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.check, - size: 40, - color: AppColors.krowCharcoal, - ), - ), - ), - const SizedBox(height: 24), - const Text( - 'Order Updated!', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - const SizedBox(height: 12), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 40), - child: Text( - 'Your shift has been updated successfully.', - textAlign: TextAlign.center, - style: TextStyle(color: Colors.white70, fontSize: 16), - ), - ), - const SizedBox(height: 40), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 40), - child: ElevatedButton( - onPressed: widget.onBack, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: AppColors.krowBlue, - minimumSize: const Size(double.infinity, 56), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - ), - child: const Text( - 'Back to Orders', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - ), - ), - ], - ), - ); - } - - Widget _buildSectionLabel(String text) { - return Padding( - padding: const EdgeInsets.only(bottom: 6), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - text, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowSlate600, - ), - ), - ), - ); - } - - Widget _buildTextField({ - required TextEditingController controller, - String? hint, - IconData? icon, - String? error, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextField( - controller: controller, - decoration: InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: AppColors.krowSlate400), - prefixIcon: icon != null - ? Icon(icon, size: 18, color: AppColors.krowSlate400) - : null, - filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 14, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: error != null - ? AppColors.krowRed500 - : AppColors.krowSlate200, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: error != null - ? AppColors.krowRed500 - : AppColors.krowSlate200, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue, width: 2), - ), - ), - ), - if (error != null) - Padding( - padding: const EdgeInsets.only(top: 4, left: 4), - child: Text( - error, - style: const TextStyle(fontSize: 11, color: AppColors.krowRed500), - ), - ), - ], - ); - } - - Widget _buildDatePicker({ - required TextEditingController controller, - String? error, - }) { - return GestureDetector( - onTap: () async { - final picked = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime.now(), - lastDate: DateTime.now().add(const Duration(days: 365)), - ); - if (picked != null) { - controller.text = picked.toIso8601String().split('T')[0]; - } - }, - child: AbsorbPointer( - child: _buildTextField( - controller: controller, - hint: 'Select Date', - icon: LucideIcons.calendar, - error: error, - ), - ), - ); - } - - Widget _buildPositionCard(int index, Map pos) { - return Container( - margin: const EdgeInsets.only(bottom: 16), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowSlate100, width: 2), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 24, - height: 24, - decoration: const BoxDecoration( - color: AppColors.krowBlue, - shape: BoxShape.circle, - ), - child: Center( - child: Text( - '${index + 1}', - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 8), - Text( - 'Position ${index + 1}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowSlate500, - ), - ), - ], - ), - if (_positions.length > 1) - GestureDetector( - onTap: () => _removePosition(index), - child: Container( - padding: const EdgeInsets.all(4), - decoration: const BoxDecoration( - color: Color(0xFFFEF2F2), // red-50 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.x, - size: 14, - color: AppColors.krowRed600, - ), - ), - ), - ], - ), - const SizedBox(height: 16), - - // Role - DropdownButtonFormField( - value: pos['role'].toString().isNotEmpty ? pos['role'] : null, - hint: const Text('Select role *'), - icon: const Icon( - LucideIcons.chevronDown, - size: 14, - color: AppColors.krowSlate600, - ), - items: _roles.map((r) { - return DropdownMenuItem( - value: r, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(r), - const SizedBox(width: 8), - Text( - '\$${_roleRates[r]?.toStringAsFixed(0)}/hr', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowSlate500, - ), - ), - ], - ), - ); - }).toList(), - onChanged: (val) => _updatePosition(index, 'role', val), - decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowSlate200), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: _errors['role_$index'] != null - ? AppColors.krowRed500 - : AppColors.krowSlate200, - ), - ), - ), - ), - if (_errors['role_$index'] != null) - Padding( - padding: const EdgeInsets.only(top: 4, left: 4), - child: Text( - _errors['role_$index']!, - style: const TextStyle( - fontSize: 11, - color: AppColors.krowRed500, - ), - ), - ), - - const SizedBox(height: 12), - - // Grid: Start, End, Workers - Row( - children: [ - Expanded(child: _buildTimeInput(index, 'start_time', 'Start *')), - const SizedBox(width: 8), - Expanded(child: _buildTimeInput(index, 'end_time', 'End *')), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Workers', - style: TextStyle( - fontSize: 11, - color: AppColors.krowSlate600, - ), - ), - const SizedBox(height: 4), - Container( - height: 48, - decoration: BoxDecoration( - border: Border.all(color: AppColors.krowSlate200), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - _buildCounterBtn( - icon: LucideIcons.minus, - onTap: () { - int count = pos['count']; - if (count > 1) - _updatePosition(index, 'count', count - 1); - }, - ), - Expanded( - child: Center( - child: Text( - '${pos['count']}', - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - ), - ), - _buildCounterBtn( - icon: LucideIcons.plus, - onTap: () { - int count = pos['count']; - _updatePosition(index, 'count', count + 1); - }, - ), - ], - ), - ), - ], - ), - ), - ], - ), - - const SizedBox(height: 12), - - // Location Override - if (pos['show_location_override'] != true) - Align( - alignment: Alignment.centerLeft, - child: TextButton.icon( - onPressed: () => - _updatePosition(index, 'show_location_override', true), - icon: const Icon(LucideIcons.mapPin, size: 14), - label: const Text('Use different location'), - style: TextButton.styleFrom( - foregroundColor: AppColors.krowBlue600, - textStyle: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - ), - ) - else - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Row( - children: [ - Icon( - LucideIcons.mapPin, - size: 14, - color: AppColors.krowSlate600, - ), - SizedBox(width: 4), - Text( - 'Different Location', - style: TextStyle( - fontSize: 12, - color: AppColors.krowSlate600, - ), - ), - ], - ), - GestureDetector( - onTap: () { - _updatePosition(index, 'show_location_override', false); - _updatePosition(index, 'location', ''); - }, - child: const Icon( - LucideIcons.x, - size: 14, - color: AppColors.krowRed600, - ), - ), - ], - ), - const SizedBox(height: 4), - TextField( - onChanged: (val) => _updatePosition(index, 'location', val), - decoration: InputDecoration( - hintText: 'Enter address', - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowSlate200, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: _errors['location_$index'] != null - ? AppColors.krowRed500 - : AppColors.krowSlate200, - ), - ), - ), - ), - if (_errors['location_$index'] != null) - Text( - _errors['location_$index']!, - style: const TextStyle( - fontSize: 11, - color: AppColors.krowRed500, - ), - ), - ], - ), - - const SizedBox(height: 12), - - // Lunch Break - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Lunch Break', - style: TextStyle(fontSize: 11, color: AppColors.krowSlate600), - ), - const SizedBox(height: 4), - DropdownButtonFormField( - value: pos['lunch_break'], - items: const [ - DropdownMenuItem(value: 0, child: Text('No break')), - DropdownMenuItem(value: 30, child: Text('30 min (Unpaid)')), - DropdownMenuItem(value: 60, child: Text('60 min (Unpaid)')), - ], - icon: const Icon( - LucideIcons.chevronDown, - size: 14, - color: AppColors.krowSlate600, - ), - onChanged: (val) => _updatePosition(index, 'lunch_break', val), - decoration: InputDecoration( - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 0, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowSlate200), - ), - ), - ), - ], - ), - - if (pos['role'].toString().isNotEmpty) ...[ - const SizedBox(height: 12), - const Divider(color: AppColors.krowSlate100), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Rate per hour', - style: TextStyle(fontSize: 12, color: AppColors.krowSlate600), - ), - Row( - children: [ - const Icon( - LucideIcons.dollarSign, - size: 14, - color: AppColors.krowEmerald600, - ), - Text( - '${_roleRates[pos['role']]?.toStringAsFixed(0)}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowEmerald600, - ), - ), - const Text( - '/hr', - style: TextStyle( - fontSize: 12, - color: AppColors.krowSlate500, - ), - ), - ], - ), - ], - ), - ], - ], - ), - ); - } - - Widget _buildTimeInput(int index, String field, String label) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.clock, - size: 12, - color: AppColors.krowSlate600, - ), - const SizedBox(width: 4), - Text( - label, - style: const TextStyle( - fontSize: 11, - color: AppColors.krowSlate600, - ), - ), - ], - ), - const SizedBox(height: 4), - GestureDetector( - onTap: () async { - final picked = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (picked != null) { - final formatted = - '${picked.hour.toString().padLeft(2, '0')}:${picked.minute.toString().padLeft(2, '0')}'; - _updatePosition(index, field, formatted); - } - }, - child: Container( - height: 48, - padding: const EdgeInsets.symmetric(horizontal: 12), - alignment: Alignment.centerLeft, - decoration: BoxDecoration( - border: Border.all( - color: _errors['${field}_$index'] != null - ? AppColors.krowRed500 - : AppColors.krowSlate200, - ), - borderRadius: BorderRadius.circular(12), - color: Colors.white, - ), - child: Text( - _positions[index][field].toString().isEmpty - ? '--:--' - : _positions[index][field], - style: TextStyle( - color: _positions[index][field].toString().isEmpty - ? AppColors.krowSlate400 - : AppColors.krowSlate900, - ), - ), - ), - ), - if (_errors['${field}_$index'] != null) - Text( - _errors['${field}_$index']!, - style: const TextStyle(fontSize: 10, color: AppColors.krowRed500), - ), - ], - ); - } - - Widget _buildCounterBtn({ - required IconData icon, - required VoidCallback onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 32, - color: Colors.transparent, - child: Icon(icon, size: 16, color: AppColors.krowSlate600), - ), - ); - } - - Widget _buildSummaryItem(String value, String label) { - return Column( - children: [ - Text( - value, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - Text( - label, - style: const TextStyle(fontSize: 12, color: AppColors.krowSlate500), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_timesheets_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_timesheets_screen.dart deleted file mode 100644 index 483060bb..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_timesheets_screen.dart +++ /dev/null @@ -1,766 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class ClientTimesheetsScreen extends StatefulWidget { - const ClientTimesheetsScreen({super.key}); - - @override - State createState() => _ClientTimesheetsScreenState(); -} - -class _ClientTimesheetsScreenState extends State - with SingleTickerProviderStateMixin { - late TabController _tabController; - final TextEditingController _searchController = TextEditingController(); - - List> _timesheets = []; - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 4, vsync: this); - _timesheets = [ - { - 'id': '1', - 'staffName': 'John Doe', - 'status': 'pending', - 'date': 'Jan 24', - 'startTime': '09:00 AM', - 'endTime': '05:00 PM', - 'totalHours': 8.0, - 'hourlyRate': 25.0, - 'totalPay': 200.00, - }, - { - 'id': '2', - 'staffName': 'Jane Smith', - 'status': 'pending', - 'date': 'Jan 24', - 'startTime': '10:00 AM', - 'endTime': '06:00 PM', - 'totalHours': 8.0, - 'hourlyRate': 22.0, - 'totalPay': 176.00, - }, - { - 'id': '3', - 'staffName': 'Mike Ross', - 'status': 'pending', - 'date': 'Jan 24', - 'startTime': '08:00 AM', - 'endTime': '12:00 PM', - 'totalHours': 4.0, - 'hourlyRate': 18.5, - 'totalPay': 74.00, - }, - { - 'id': '4', - 'staffName': 'Alice Wonderland', - 'status': 'approved', - 'date': 'Jan 23', - 'startTime': '09:00 AM', - 'endTime': '05:00 PM', - 'totalHours': 8.0, - 'hourlyRate': 25.0, - 'totalPay': 200.00, - }, - { - 'id': '5', - 'staffName': 'Bob The Builder', - 'status': 'paid', - 'date': 'Jan 22', - 'startTime': '10:00 AM', - 'endTime': '06:00 PM', - 'totalHours': 8.0, - 'hourlyRate': 22.0, - 'totalPay': 176.00, - }, - { - 'id': '6', - 'staffName': 'Charlie Chaplin', - 'status': 'disputed', - 'date': 'Jan 21', - 'startTime': '08:00 AM', - 'endTime': '12:00 PM', - 'totalHours': 4.0, - 'hourlyRate': 18.5, - 'totalPay': 74.00, - }, - ]; - } - - void _approveTimesheet(String id) { - setState(() { - final index = _timesheets.indexWhere((ts) => ts['id'] == id); - if (index != -1) { - _timesheets[index]['status'] = 'approved'; - } - }); - } - - void _disputeTimesheet(String id) { - setState(() { - final index = _timesheets.indexWhere((ts) => ts['id'] == id); - if (index != -1) { - _timesheets[index]['status'] = 'disputed'; - } - }); - } - - void _approveAllPendingTimesheets() { - setState(() { - for (var ts in _timesheets) { - if (ts['status'] == 'pending') { - ts['status'] = 'approved'; - } - } - }); - } - - @override - void dispose() { - _tabController.dispose(); - _searchController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: SafeArea( - child: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) { - return [ - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header Row - Row( - children: [ - GestureDetector( - onTap: () => context.go('/client-home'), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.grey.shade100, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: AppColors.krowCharcoal, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Timesheets', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const SizedBox(height: 16), - - // Summary Cards - Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.amber.shade50, - Colors.yellow.shade50, - ], - ), - borderRadius: BorderRadius.circular(12), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - LucideIcons.clock, - size: 14, - color: Colors.amber.shade600, - ), - const SizedBox(width: 4), - Text( - 'Pending', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ), - const SizedBox(height: 4), - const Text( - '3 timesheets', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 2), - Text( - '\$450.00', - style: TextStyle( - fontSize: 14, - color: Colors.amber.shade700, - ), - ), - ], - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.green.shade50, - Colors.greenAccent.shade100.withOpacity( - 0.2, - ), - ], // Changed from emerald - ), - borderRadius: BorderRadius.circular(12), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - LucideIcons.checkCircle, - size: 14, - color: Colors.green.shade600, - ), // Changed from emerald - const SizedBox(width: 4), - Text( - 'Approved', - style: TextStyle( - fontSize: 12, - color: Colors.grey.shade600, - ), - ), - ], - ), - const SizedBox(height: 4), - const Text( - 'This Week', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 2), - Text( - '\$1,200.00', - style: TextStyle( - fontSize: 14, - color: Colors.green.shade700, - ), // Changed from emerald - ), - ], - ), - ), - ), - ], - ), - - const SizedBox(height: 16), - // Search Bar - TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search by worker name...', - prefixIcon: const Icon( - LucideIcons.search, - color: AppColors.krowMuted, - ), - filled: true, - fillColor: Colors.white, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric( - vertical: 0, - ), - ), - ), - const SizedBox(height: 16), - // Tabs - Container( - height: 36, - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(10), - ), - child: TabBar( - controller: _tabController, - indicator: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - ), - ], - ), - labelColor: AppColors.krowCharcoal, - unselectedLabelColor: AppColors.krowMuted, - labelStyle: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - padding: const EdgeInsets.all(2), - indicatorSize: TabBarIndicatorSize.tab, - tabs: [ - Tab( - text: - 'Pending (${_timesheets.where((ts) => ts['status'] == 'pending').length})', - ), - Tab( - text: - 'Approved (${_timesheets.where((ts) => ts['status'] == 'approved').length})', - ), - Tab( - text: - 'Paid (${_timesheets.where((ts) => ts['status'] == 'paid').length})', - ), - Tab( - text: - 'Disputed (${_timesheets.where((ts) => ts['status'] == 'disputed').length})', - ), - ], - ), - ), - ], - ), - ), - ), - ]; - }, - body: TabBarView( - controller: _tabController, - children: [ - _TimesheetList( - timesheets: _timesheets - .where((ts) => ts['status'] == 'pending') - .toList(), - onApproveAll: _approveAllPendingTimesheets, - onApprove: _approveTimesheet, - onDispute: _disputeTimesheet, - ), - _TimesheetList( - timesheets: _timesheets - .where((ts) => ts['status'] == 'approved') - .toList(), - onApproveAll: - _approveAllPendingTimesheets, // Still needed for consistency - onApprove: _approveTimesheet, - onDispute: _disputeTimesheet, - ), - _TimesheetList( - timesheets: _timesheets - .where((ts) => ts['status'] == 'paid') - .toList(), - onApproveAll: - _approveAllPendingTimesheets, // Still needed for consistency - onApprove: _approveTimesheet, - onDispute: _disputeTimesheet, - ), - _TimesheetList( - timesheets: _timesheets - .where((ts) => ts['status'] == 'disputed') - .toList(), - onApproveAll: - _approveAllPendingTimesheets, // Still needed for consistency - onApprove: _approveTimesheet, - onDispute: _disputeTimesheet, - ), - ], - ), - ), - ), - floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, - floatingActionButton: Padding( - padding: const EdgeInsets.only(bottom: 80), - child: SizedBox( - height: 48, - child: ElevatedButton.icon( - onPressed: () {}, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: AppColors.krowCharcoal, - elevation: 4, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - side: BorderSide(color: Colors.grey.shade200), - ), - icon: const Icon(LucideIcons.download, size: 18), - label: const Text('Export Timesheets'), - ), - ), - ), - ); - } -} - -class _TimesheetList extends StatelessWidget { - final List> timesheets; - final VoidCallback onApproveAll; - final Function(String id) onApprove; - final Function(String id) onDispute; - - const _TimesheetList({ - super.key, - required this.timesheets, - required this.onApproveAll, - required this.onApprove, - required this.onDispute, - }); - - @override - Widget build(BuildContext context) { - if (timesheets.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - LucideIcons.clock, - size: 48, - color: AppColors.krowBorder, - ), - const SizedBox(height: 16), - Text( - 'No timesheets', - style: const TextStyle(color: AppColors.krowMuted), - ), - ], - ), - ); - } - - // Determine if any timesheets are pending for the "Approve All" banner - final bool hasPendingTimesheets = timesheets.any( - (ts) => ts['status'] == 'pending', - ); - final int pendingCount = timesheets - .where((ts) => ts['status'] == 'pending') - .length; - - return ListView( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 140), - children: [ - if (hasPendingTimesheets) - // Approve All Banner - Container( - padding: const EdgeInsets.all(12), - margin: const EdgeInsets.only(bottom: 16), - decoration: BoxDecoration( - color: Colors.purple.shade50, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.purple.shade100), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '$pendingCount pending approval', - style: TextStyle( - color: Colors.purple.shade700, - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), - ElevatedButton.icon( - onPressed: onApproveAll, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.purple.shade600, - foregroundColor: Colors.white, - elevation: 0, - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - minimumSize: Size.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - icon: const Icon(LucideIcons.checkCircle, size: 14), - label: const Text( - 'Approve All', - style: TextStyle(fontSize: 12), - ), - ), - ], - ), - ), - - ...timesheets.map( - (timesheet) => Padding( - padding: const EdgeInsets.only(bottom: 12), - child: _TimesheetCard( - timesheet: timesheet, - onApprove: onApprove, - onDispute: onDispute, - ), - ), - ), - ], - ); - } -} - -class _TimesheetCard extends StatelessWidget { - final Map timesheet; - final Function(String id) onApprove; - final Function(String id) onDispute; - - const _TimesheetCard({ - super.key, - required this.timesheet, - required this.onApprove, - required this.onDispute, - }); - - @override - Widget build(BuildContext context) { - final String staffName = timesheet['staffName']; - final String status = timesheet['status']; - final String date = timesheet['date']; - final String startTime = timesheet['startTime']; - final String endTime = timesheet['endTime']; - final double totalHours = timesheet['totalHours']; - final double hourlyRate = timesheet['hourlyRate']; - final double totalPay = timesheet['totalPay']; - - Color statusBg; - Color statusText; - - switch (status) { - case 'pending': - statusBg = Colors.amber.shade100; - statusText = Colors.amber.shade700; - break; - case 'approved': - statusBg = Colors.green.shade100; - statusText = Colors.green.shade700; - break; - case 'paid': - statusBg = Colors.blue.shade100; - statusText = Colors.blue.shade700; - break; - case 'disputed': - statusBg = Colors.red.shade100; - statusText = Colors.red.shade700; - break; - default: - statusBg = Colors.grey.shade100; - statusText = Colors.grey.shade700; - } - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.purple.shade100, - shape: BoxShape.circle, - ), - child: Center( - child: Text( - staffName[0], - style: TextStyle( - color: Colors.purple.shade700, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - staffName, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: statusBg, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - status.toUpperCase(), - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: statusText, - ), - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Icon( - LucideIcons.calendar, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - date, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 12), - Icon( - LucideIcons.clock, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - '$startTime - $endTime', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - const SizedBox(height: 12), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Text( - '$totalHours hrs', - style: const TextStyle( - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(width: 4), - Text( - '@ \$$hourlyRate/hr', - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - Text( - '\$${totalPay.toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - if (status == 'pending') ...[ - const SizedBox(height: 12), - Row( - children: [ - Expanded( - child: ElevatedButton.icon( - onPressed: () => onApprove(timesheet['id']), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.green.shade500, - foregroundColor: Colors.white, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - icon: const Icon(LucideIcons.checkCircle, size: 14), - label: const Text('Approve'), - ), - ), - const SizedBox(width: 12), - Expanded( - child: OutlinedButton.icon( - onPressed: () => onDispute(timesheet['id']), - style: OutlinedButton.styleFrom( - foregroundColor: Colors.red.shade600, - side: BorderSide(color: Colors.red.shade200), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - icon: const Icon(LucideIcons.alertCircle, size: 14), - label: const Text('Dispute'), - ), - ), - ], - ), - ], - ], - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_workers_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_workers_screen.dart deleted file mode 100644 index b5eeb0b3..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/client_workers_screen.dart +++ /dev/null @@ -1,747 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class ClientWorkersScreen extends StatefulWidget { - const ClientWorkersScreen({super.key}); - - @override - State createState() => _ClientWorkersScreenState(); -} - -class _ClientWorkersScreenState extends State - with SingleTickerProviderStateMixin { - late TabController _tabController; - final TextEditingController _searchController = TextEditingController(); - - @override - void initState() { - super.initState(); - _tabController = TabController(length: 3, vsync: this); - } - - @override - void dispose() { - _tabController.dispose(); - _searchController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: SafeArea( - child: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) { - return [ - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Header Row - Row( - children: [ - GestureDetector( - onTap: () => context.go('/client-home'), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.grey.shade100, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: AppColors.krowCharcoal, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Smart Assign', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const SizedBox(height: 16), - // Search Bar - TextField( - controller: _searchController, - decoration: InputDecoration( - hintText: 'Search workers by name or skill...', - prefixIcon: const Icon( - LucideIcons.search, - color: AppColors.krowMuted, - ), - filled: true, - fillColor: Colors.white, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric( - vertical: 0, - ), - ), - ), - const SizedBox(height: 16), - // Tabs and Filter - Row( - children: [ - Expanded( - child: Container( - height: 36, - decoration: BoxDecoration( - color: Colors.grey.shade200, - borderRadius: BorderRadius.circular(10), - ), - child: TabBar( - controller: _tabController, - indicator: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - ), - ], - ), - labelColor: AppColors.krowCharcoal, - unselectedLabelColor: AppColors.krowMuted, - labelStyle: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - padding: const EdgeInsets.all(2), - indicatorSize: TabBarIndicatorSize.tab, - tabs: const [ - Tab( - child: FittedBox( - fit: BoxFit.scaleDown, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Icon(LucideIcons.sparkles, size: 12), - SizedBox(width: 4), - Text('AI Picks'), - ], - ), - ), - ), - Tab( - child: FittedBox( - fit: BoxFit.scaleDown, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Icon(LucideIcons.star, size: 12), - SizedBox(width: 4), - Text('Top Rated'), - ], - ), - ), - ), - Tab( - child: FittedBox( - fit: BoxFit.scaleDown, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Icon(LucideIcons.users, size: 12), - SizedBox(width: 4), - Text('Past'), - ], - ), - ), - ), - ], - ), - ), - ), - const SizedBox(width: 8), - GestureDetector( - onTap: () => _showFilterSheet(context), - child: Container( - height: 36, - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - border: Border.all(color: AppColors.krowBorder), - ), - child: const Row( - children: [ - Icon( - LucideIcons.filter, - size: 14, - color: AppColors.krowCharcoal, - ), - SizedBox(width: 4), - Text( - 'Filters', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ], - ), - ], - ), - ), - ), - ]; - }, - body: TabBarView( - controller: _tabController, - children: [ - _WorkerList(type: 'recommended'), - _WorkerList(type: 'top-rated'), - _WorkerList(type: 'past'), - ], - ), - ), - ), - ); - } - - void _showFilterSheet(BuildContext context) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) => const _FilterSheet(), - ); - } -} - -class _FilterSheet extends StatefulWidget { - const _FilterSheet(); - - @override - State<_FilterSheet> createState() => _FilterSheetState(); -} - -class _FilterSheetState extends State<_FilterSheet> { - double _minRating = 4.0; - double _reliabilityScore = 80.0; - bool _certifiedOnly = false; - bool _pastWorkersOnly = false; - - @override - Widget build(BuildContext context) { - return Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(24)), - ), - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Filter Workers', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - IconButton( - icon: const Icon(LucideIcons.x, color: AppColors.krowMuted), - onPressed: () => Navigator.pop(context), - ), - ], - ), - const SizedBox(height: 24), - - // Min Rating - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Minimum Rating', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), // slate-700 - ), - ), - Text( - '${_minRating.toStringAsFixed(1)}+ stars', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF7C3AED), // violet-600 - ), - ), - ], - ), - Slider( - value: _minRating, - min: 1.0, - max: 5.0, - divisions: 8, - activeColor: const Color(0xFF7C3AED), // violet-600 - onChanged: (value) => setState(() => _minRating = value), - ), - const SizedBox(height: 20), - - // Reliability Score - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Reliability Score', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), // slate-700 - ), - ), - Text( - '${_reliabilityScore.toInt()}%+', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF7C3AED), // violet-600 - ), - ), - ], - ), - Slider( - value: _reliabilityScore, - min: 50.0, - max: 100.0, - divisions: 10, - activeColor: const Color(0xFF7C3AED), // violet-600 - onChanged: (value) => setState(() => _reliabilityScore = value), - ), - const SizedBox(height: 20), - - // Checkboxes - _buildCheckbox( - 'Certified Only', - LucideIcons.award, - Colors.amber, - _certifiedOnly, - (v) => setState(() => _certifiedOnly = v ?? false), - ), - const SizedBox(height: 12), - _buildCheckbox( - 'Past Workers Only', - LucideIcons.users, - Colors.blue, - _pastWorkersOnly, - (v) => setState(() => _pastWorkersOnly = v ?? false), - ), - - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () { - // Apply filters logic would go here - Navigator.pop(context); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF7C3AED), // violet-600 - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - textStyle: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - child: const Text('Apply Filters'), - ), - ), - const SizedBox(height: 24), // Bottom padding - ], - ), - ); - } - - Widget _buildCheckbox( - String label, - IconData icon, - Color iconColor, - bool value, - ValueChanged onChanged, - ) { - return InkWell( - onTap: () => onChanged(!value), - borderRadius: BorderRadius.circular(8), - child: Row( - children: [ - Checkbox( - value: value, - onChanged: onChanged, - activeColor: const Color(0xFF7C3AED), // violet-600 - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - ), - Icon(icon, size: 16, color: iconColor), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), // slate-700 - ), - ), - ], - ), - ); - } -} - -class _WorkerList extends StatelessWidget { - final String type; - - const _WorkerList({required this.type}); - - @override - Widget build(BuildContext context) { - return ListView( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 100), - children: [ - if (type == 'recommended') - Container( - margin: const EdgeInsets.only(bottom: 20), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.purple.shade50, Colors.deepPurple.shade50], - ), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.purple.shade100), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.purple.shade100, - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.sparkles, - color: Colors.purple, - size: 20, - ), - ), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'AI-Powered Matching', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - SizedBox(height: 4), - Text( - 'Workers ranked by performance, reliability, skills match, and past work history with your company.', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - ], - ), - ), - - const Text( - '12 workers found', - style: TextStyle(fontSize: 14, color: AppColors.krowMuted), - ), - const SizedBox(height: 12), - - // Mock Staff / Workers - _WorkerCard( - name: 'Sarah Wilson', - role: 'Head Server', - averageRating: 4.9, - totalShifts: 142, - reliabilityScore: 98, - isRecommended: type == 'recommended', - photoUrl: 'https://i.pravatar.cc/150?u=sarah', - ), - const SizedBox(height: 12), - _WorkerCard( - name: 'Michael Chen', - role: 'Bartender', - averageRating: 4.8, - totalShifts: 89, - reliabilityScore: 95, - isRecommended: type == 'recommended', - photoUrl: 'https://i.pravatar.cc/150?u=michael', - ), - const SizedBox(height: 12), - _WorkerCard( - name: 'Jessica Davis', - role: 'Event Staff', - averageRating: 4.7, - totalShifts: 215, - reliabilityScore: 92, - isRecommended: false, // Only top 2 recommended - photoUrl: 'https://i.pravatar.cc/150?u=jessica', - ), - ], - ); - } -} - -class _WorkerCard extends StatelessWidget { - final String name; - final String role; - final double averageRating; - final int totalShifts; - final int reliabilityScore; - final bool isRecommended; - final String photoUrl; - - const _WorkerCard({ - required this.name, - required this.role, - required this.averageRating, - required this.totalShifts, - required this.reliabilityScore, - required this.isRecommended, - required this.photoUrl, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: isRecommended ? Colors.purple.shade200 : AppColors.krowBorder, - width: isRecommended ? 1.5 : 1, - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 8, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Avatar - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - image: DecorationImage( - image: NetworkImage(photoUrl), - fit: BoxFit.cover, - ), - ), - ), - const SizedBox(width: 12), - // Info - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - name, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - overflow: TextOverflow.ellipsis, - ), - ), - if (isRecommended) - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 2, - ), - decoration: BoxDecoration( - color: Colors.purple.shade50, - borderRadius: BorderRadius.circular(100), - border: Border.all(color: Colors.purple.shade100), - ), - child: Row( - children: [ - Icon( - LucideIcons.sparkles, - size: 10, - color: Colors.purple.shade600, - ), - const SizedBox(width: 4), - Text( - 'Best Match', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.purple.shade700, - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - role, - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 8), - // Stats Row - Wrap( - spacing: 8, - runSpacing: 4, - children: [ - _StatBadge( - icon: LucideIcons.star, - text: '$averageRating', - color: Colors.amber, - ), - _StatBadge( - icon: LucideIcons.briefcase, - text: '$totalShifts jobs', - color: Colors.blue, - ), - _StatBadge( - icon: LucideIcons.shieldCheck, - text: '$reliabilityScore%', - color: Colors.green, - ), - ], - ), - ], - ), - ), - ], - ), - const SizedBox(height: 16), - // Buttons - Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () {}, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12), - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: const Text( - 'View Profile', - style: TextStyle(color: AppColors.krowCharcoal), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: ElevatedButton( - onPressed: () {}, - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 12), - backgroundColor: AppColors.krowBlue, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: const Text( - 'Direct Offer', - style: TextStyle(color: Colors.white), - ), - ), - ), - ], - ), - ], - ), - ); - } -} - -class _StatBadge extends StatelessWidget { - final IconData icon; - final String text; - final Color color; - - const _StatBadge({ - required this.icon, - required this.text, - required this.color, - }); - - @override - Widget build(BuildContext context) { - return Row( - children: [ - Icon(icon, size: 12, color: color), - const SizedBox(width: 4), - Text( - text, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/coverage_dashboard.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/coverage_dashboard.dart deleted file mode 100644 index 109f170c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/coverage_dashboard.dart +++ /dev/null @@ -1,330 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class CoverageDashboard extends StatelessWidget { - const CoverageDashboard({ - super.key, - required this.shifts, - required this.applications, - }); - - final List shifts; - final List applications; - - @override - Widget build(BuildContext context) { - // Mock Data Logic (simulating React component) - final todayShifts = - shifts; // Assuming shifts passed are already filtered or we treat all as 'today' for mock - - // Calculate coverage stats - // Mock data structures: - // shift: { workersNeeded: int, filled: int, status: String, hourlyRate: double } - // application: { status: String, checkInTime: String? } - - int totalNeeded = 0; - int totalConfirmed = 0; - double todayCost = 0; - - for (var s in todayShifts) { - // Handle map or object access safely for mock - final needed = s['workersNeeded'] as int? ?? 0; - final confirmed = s['filled'] as int? ?? 0; - final rate = s['hourlyRate'] as double? ?? 20.0; - - totalNeeded += needed; - totalConfirmed += confirmed; - todayCost += rate * 8 * confirmed; // 8 hours avg - } - - final coveragePercent = totalNeeded > 0 - ? ((totalConfirmed / totalNeeded) * 100).round() - : 100; - final unfilledPositions = totalNeeded - totalConfirmed; - - // Mock status counts from applications - final checkedInCount = applications - .where((a) => a['checkInTime'] != null) - .length; - final lateWorkersCount = applications - .where((a) => a['status'] == 'LATE') - .length; - - // Colors - final isCoverageGood = coveragePercent >= 90; - final coverageBadgeColor = isCoverageGood - ? const Color(0xFFD1FAE5) - : const Color(0xFFFEF3C7); // emerald-100 vs amber-100 - final coverageTextColor = isCoverageGood - ? const Color(0xFF047857) - : const Color(0xFFB45309); // emerald-700 vs amber-700 - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: AppColors.krowBorder, - ), // border-0 in React but typically cards have borders in Flutter or shadow - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 4, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - // Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - "Today's Status", - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: coverageBadgeColor, - borderRadius: BorderRadius.circular(10), - ), - child: Text( - '$coveragePercent% Covered', - style: TextStyle( - fontSize: 10, // approximate text-xs/Badge size - fontWeight: FontWeight.bold, - color: coverageTextColor, - ), - ), - ), - ], - ), - const SizedBox(height: 16), - - // Grid - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Column 1 - Expanded( - child: Column( - children: [ - // Unfilled / Filled Status - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: unfilledPositions > 0 - ? const Color(0xFFFFFBEB) - : const Color(0xFFECFDF5), // amber-50 : emerald-50 - border: Border.all( - color: unfilledPositions > 0 - ? const Color(0xFFFDE68A) - : const Color( - 0xFFA7F3D0, - ), // amber-200 : emerald-200 - ), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - LucideIcons.alertTriangle, - size: 16, - color: unfilledPositions > 0 - ? const Color(0xFFD97706) - : const Color( - 0xFF059669, - ), // amber-600 : emerald-600 - ), - const SizedBox(width: 8), - Text( - 'Unfilled Today', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: unfilledPositions > 0 - ? const Color(0xFF78350F) - : const Color( - 0xFF064E3B, - ), // amber-900 : emerald-900 - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - '$unfilledPositions', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: unfilledPositions > 0 - ? const Color(0xFFB45309) - : const Color( - 0xFF047857, - ), // amber-700 : emerald-700 - ), - ), - ], - ), - ), - const SizedBox(height: 8), - // Running Late (Conditional) - if (lateWorkersCount > 0) - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFFEF2F2), // red-50 - border: Border.all( - color: const Color(0xFFFECACA), - ), // red-200 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.alertTriangle, - size: 16, - color: Color(0xFFDC2626), // red-600 - ), - const SizedBox(width: 8), - const Text( - 'Running Late', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF7F1D1D), // red-900 - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - '$lateWorkersCount', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFFB91C1C), // red-700 - ), - ), - ], - ), - ), - ], - ), - ), - const SizedBox(width: 8), - // Column 2 - Expanded( - child: Column( - children: [ - // Checked In - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), // blue-50 - border: Border.all( - color: const Color(0xFFBFDBFE), - ), // blue-200 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.checkCircle, - size: 16, - color: Color(0xFF2563EB), // blue-600 - ), - const SizedBox(width: 8), - const Text( - 'Checked In', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF1E3A8A), // blue-900 - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - '$checkedInCount/$totalConfirmed', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF1D4ED8), // blue-700 - ), - ), - ], - ), - ), - const SizedBox(height: 8), - // Today's Cost - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), // blue-50 - border: Border.all( - color: const Color(0xFFBFDBFE), - ), // blue-200 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.dollarSign, - size: 16, - color: Color(0xFF2563EB), // blue-600 - ), - const SizedBox(width: 8), - const Text( - 'Today\'s Cost', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF1E3A8A), // blue-900 - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - '\$${todayCost.round()}', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF1D4ED8), // blue-700 - ), - ), - ], - ), - ), - ], - ), - ), - ], - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/one_time_order_flow_page.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/one_time_order_flow_page.dart deleted file mode 100644 index 23a9bd7c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/one_time_order_flow_page.dart +++ /dev/null @@ -1,789 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; - -// Color constants from React - Global access -const Color reactPrimary = Color(0xFF0A39DF); -const Color reactAccent = Color(0xFFF9E547); -const Color reactForeground = Color(0xFF121826); -const Color reactMuted = Color(0xFF6A7382); -const Color reactBackground = Color(0xFFFAFBFC); -const Color reactBorder = Color(0xFFE3E6E9); - -class OneTimeOrderFlowPage extends StatefulWidget { - const OneTimeOrderFlowPage({super.key}); - - @override - State createState() => _OneTimeOrderFlowPageState(); -} - -class _Position { - String role; - int count; - String startTime; - String endTime; - int lunchBreak; - String location; - bool showLocationOverride; - - _Position({ - this.role = '', - this.count = 1, - this.startTime = '', - this.endTime = '', - this.lunchBreak = 30, - this.location = '', - this.showLocationOverride = false, - }); -} - -class _OneTimeOrderFlowPageState extends State { - bool _submitted = false; - bool _isCreating = false; - - final TextEditingController _dateController = TextEditingController(); - final TextEditingController _locationController = TextEditingController(); - - final List<_Position> _positions = [_Position()]; - - final List> _roles = [ - {'name': 'Server', 'rate': 18.0}, - {'name': 'Bartender', 'rate': 22.0}, - {'name': 'Cook', 'rate': 20.0}, - {'name': 'Busser', 'rate': 16.0}, - {'name': 'Host', 'rate': 17.0}, - {'name': 'Barista', 'rate': 16.0}, - {'name': 'Dishwasher', 'rate': 15.0}, - {'name': 'Event Staff', 'rate': 20.0}, - ]; - - void _addPosition() { - setState(() { - _positions.add(_Position()); - }); - } - - void _removePosition(int index) { - if (_positions.length > 1) { - setState(() { - _positions.removeAt(index); - }); - } - } - - void _updatePosition(int index, String field, dynamic value) { - setState(() { - if (field == 'role') { - _positions[index].role = value; - } else if (field == 'count') { - _positions[index].count = value; - } else if (field == 'startTime') { - _positions[index].startTime = value; - } else if (field == 'endTime') { - _positions[index].endTime = value; - } else if (field == 'lunchBreak') { - _positions[index].lunchBreak = value; - } else if (field == 'location') { - _positions[index].location = value; - } else if (field == 'showLocationOverride') { - _positions[index].showLocationOverride = value; - } - }); - } - - Future _handleSubmit() async { - setState(() => _isCreating = true); - await Future.delayed(const Duration(milliseconds: 800)); - if (mounted) { - setState(() { - _isCreating = false; - _submitted = true; - }); - } - } - - @override - Widget build(BuildContext context) { - if (_submitted) { - return const _SuccessView(); - } - - return Scaffold( - backgroundColor: reactBackground, - body: Column( - children: [ - // Header - Container( - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 20, - bottom: 20, - left: 20, - right: 20, - ), - color: reactPrimary, - child: Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 24, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'One-Time Order', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Single event or shift request', - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.8), - ), - ), - ], - ), - ], - ), - ), - - // Content - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Create Your Order', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 16), - - // Date - _buildLabel('Date'), - const SizedBox(height: 6), - _buildInputField( - controller: _dateController, - hint: 'Select date', - icon: LucideIcons.calendar, - readOnly: true, - onTap: () async { - final picked = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime.now(), - lastDate: DateTime.now().add(const Duration(days: 365)), - ); - if (picked != null) { - _dateController.text = DateFormat( - 'yyyy-MM-dd', - ).format(picked); - } - }, - ), - const SizedBox(height: 16), - - // Location - _buildLabel('Location'), - const SizedBox(height: 6), - _buildInputField( - controller: _locationController, - hint: 'Enter address', - icon: LucideIcons.mapPin, - ), - - const SizedBox(height: 24), - - // Positions Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Positions', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), - ), - ), - GestureDetector( - onTap: _addPosition, - child: const Row( - children: [ - Icon( - LucideIcons.plus, - size: 16, - color: Color(0xFF0032A0), - ), - SizedBox(width: 4), - Text( - 'Add Position', - style: TextStyle( - color: Color(0xFF0032A0), - fontSize: 14, - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - - // Positions List - ..._positions.asMap().entries.map((entry) { - return _buildPositionCard(entry.key, entry.value); - }), - ], - ), - ), - ), - - // Footer - Container( - padding: EdgeInsets.only( - left: 20, - right: 20, - top: 20, - bottom: MediaQuery.of(context).padding.bottom + 20, - ), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: reactBorder)), - ), - child: SizedBox( - width: double.infinity, - height: 52, - child: ElevatedButton( - onPressed: _isCreating ? null : _handleSubmit, - style: ElevatedButton.styleFrom( - backgroundColor: reactPrimary, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: Text( - _isCreating ? 'Creating...' : 'Create Order', - style: const TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - ); - } - - Widget _buildLabel(String text) { - return Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF475569), - ), - ); - } - - Widget _buildInputField({ - required TextEditingController controller, - required String hint, - required IconData icon, - bool readOnly = false, - VoidCallback? onTap, - }) { - return Container( - height: 48, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: reactBorder), - ), - child: TextField( - controller: controller, - readOnly: readOnly, - onTap: onTap, - decoration: InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Color(0xFF94A3B8), fontSize: 14), - prefixIcon: Icon(icon, size: 18, color: Color(0xFF94A3B8)), - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 13), - ), - ), - ); - } - - Widget _buildPositionCard(int index, _Position pos) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Color(0xFFF1F5F9)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Position ${index + 1}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: reactMuted, - ), - ), - if (_positions.length > 1) - GestureDetector( - onTap: () => _removePosition(index), - child: const Text( - 'Remove', - style: TextStyle( - fontSize: 12, - color: Colors.red, - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ), - const SizedBox(height: 12), - - // Role Selector - Container( - padding: const EdgeInsets.symmetric(horizontal: 12), - height: 44, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - border: Border.all(color: reactBorder), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - isExpanded: true, - hint: const Text('Select role', style: TextStyle(fontSize: 14)), - value: pos.role.isEmpty ? null : pos.role, - icon: const Icon( - LucideIcons.chevronDown, - size: 18, - color: reactMuted, - ), - onChanged: (val) => _updatePosition(index, 'role', val), - items: _roles.map((role) { - final String name = role['name'] as String; - final double rate = role['rate'] as double; - return DropdownMenuItem( - value: name, - child: Text( - '$name - \$${rate.toStringAsFixed(0)}/hr', - style: const TextStyle(fontSize: 14), - ), - ); - }).toList(), - ), - ), - ), - - const SizedBox(height: 12), - - Row( - children: [ - // Start Time - Expanded( - child: _buildTimeInput( - label: 'Start', - value: pos.startTime, - onTap: () async { - final time = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (time != null) - _updatePosition(index, 'startTime', time.format(context)); - }, - ), - ), - const SizedBox(width: 8), - // End Time - Expanded( - child: _buildTimeInput( - label: 'End', - value: pos.endTime, - onTap: () async { - final time = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (time != null) - _updatePosition(index, 'endTime', time.format(context)); - }, - ), - ), - const SizedBox(width: 8), - // Workers Count - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Workers', - style: TextStyle(fontSize: 12, color: reactMuted), - ), - const SizedBox(height: 4), - Container( - height: 40, - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - GestureDetector( - onTap: () => _updatePosition( - index, - 'count', - (pos.count > 1) ? pos.count - 1 : 1, - ), - child: const Icon(LucideIcons.minus, size: 12), - ), - Text( - '${pos.count}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 13, - ), - ), - GestureDetector( - onTap: () => - _updatePosition(index, 'count', pos.count + 1), - child: const Icon(LucideIcons.plus, size: 12), - ), - ], - ), - ), - ], - ), - ), - ], - ), - - const SizedBox(height: 16), - - // Optional Location Override - if (!pos.showLocationOverride) - GestureDetector( - onTap: () => _updatePosition(index, 'showLocationOverride', true), - child: const Row( - children: [ - Icon(LucideIcons.mapPin, size: 14, color: Color(0xFF2563EB)), - SizedBox(width: 4), - Text( - 'Use different location for this position', - style: TextStyle( - fontSize: 12, - color: Color(0xFF2563EB), - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ) - else - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Row( - children: [ - Icon(LucideIcons.mapPin, size: 14, color: reactMuted), - SizedBox(width: 4), - Text( - 'Different Location', - style: TextStyle( - fontSize: 12, - color: reactMuted, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - GestureDetector( - onTap: () { - _updatePosition(index, 'showLocationOverride', false); - _updatePosition(index, 'location', ''); - }, - child: const Icon( - LucideIcons.x, - size: 14, - color: Colors.red, - ), - ), - ], - ), - const SizedBox(height: 6), - Container( - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: reactBorder), - ), - child: TextField( - onChanged: (val) => _updatePosition(index, 'location', val), - style: const TextStyle(fontSize: 13), - decoration: const InputDecoration( - hintText: 'Enter different address', - hintStyle: TextStyle( - color: Color(0xFF94A3B8), - fontSize: 13, - ), - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 12, - vertical: 10, - ), - ), - ), - ), - ], - ), - - const SizedBox(height: 12), - - // Lunch Break - const Text( - 'Lunch Break', - style: TextStyle(fontSize: 12, color: reactMuted), - ), - const SizedBox(height: 4), - Container( - height: 44, - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - border: Border.all(color: reactBorder), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - isExpanded: true, - value: pos.lunchBreak, - icon: const Icon( - LucideIcons.chevronDown, - size: 18, - color: reactMuted, - ), - onChanged: (val) => _updatePosition(index, 'lunchBreak', val), - items: const [ - DropdownMenuItem( - value: 0, - child: Text('No break', style: TextStyle(fontSize: 14)), - ), - DropdownMenuItem( - value: 10, - child: Text( - '10 min (Paid)', - style: TextStyle(fontSize: 14), - ), - ), - DropdownMenuItem( - value: 15, - child: Text( - '15 min (Paid)', - style: TextStyle(fontSize: 14), - ), - ), - DropdownMenuItem( - value: 30, - child: Text( - '30 min (Unpaid)', - style: TextStyle(fontSize: 14), - ), - ), - DropdownMenuItem( - value: 45, - child: Text( - '45 min (Unpaid)', - style: TextStyle(fontSize: 14), - ), - ), - DropdownMenuItem( - value: 60, - child: Text( - '60 min (Unpaid)', - style: TextStyle(fontSize: 14), - ), - ), - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildTimeInput({ - required String label, - required String value, - required VoidCallback onTap, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(label, style: const TextStyle(fontSize: 12, color: reactMuted)), - const SizedBox(height: 4), - GestureDetector( - onTap: onTap, - child: Container( - height: 40, - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: reactBorder), - ), - alignment: Alignment.centerLeft, - child: Text( - value.isEmpty ? '--:--' : value, - style: const TextStyle(fontSize: 13), - ), - ), - ), - ], - ); - } -} - -class _SuccessView extends StatelessWidget { - const _SuccessView(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Color(0xFF0A39DF), Color(0xFF0830B8)], - ), - ), - child: SafeArea( - child: Center( - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 40), - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: reactAccent, - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.check, - color: reactForeground, - size: 32, - ), - ), - ), - const SizedBox(height: 24), - const Text( - 'Order Created!', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: reactForeground, - ), - ), - const SizedBox(height: 12), - const Text( - 'Your shift request has been posted. Workers will start applying soon.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: reactMuted, - height: 1.5, - ), - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 52, - child: ElevatedButton( - onPressed: () => context.pop(), - style: ElevatedButton.styleFrom( - backgroundColor: reactPrimary, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: const Text( - 'Back to Orders', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/permanent_order_flow_page.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/permanent_order_flow_page.dart deleted file mode 100644 index 22e00b83..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/permanent_order_flow_page.dart +++ /dev/null @@ -1,1222 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../../theme.dart'; - -class PermanentOrderFlowPage extends StatefulWidget { - const PermanentOrderFlowPage({super.key}); - - @override - State createState() => _PermanentOrderFlowPageState(); -} - -class _Schedule { - List selectedDays; - String startTime; - String endTime; - - _Schedule({ - required this.selectedDays, - this.startTime = '', - this.endTime = '', - }); - - _Schedule copy() => _Schedule( - selectedDays: List.from(selectedDays), - startTime: startTime, - endTime: endTime, - ); -} - -class _Position { - String role; - String employmentType; - double salaryMin; - double salaryMax; - int count; - String description; - String requirements; - List<_Schedule> schedules; - - _Position({ - this.role = '', - this.employmentType = '', - this.salaryMin = 0, - this.salaryMax = 0, - this.count = 1, - this.description = '', - this.requirements = '', - required this.schedules, - }); - - _Position copy() => _Position( - role: role, - employmentType: employmentType, - salaryMin: salaryMin, - salaryMax: salaryMax, - count: count, - description: description, - requirements: requirements, - schedules: schedules.map((s) => s.copy()).toList(), - ); -} - -class _PermanentOrderFlowPageState extends State { - bool _submitted = false; - bool _showReview = false; - int _openPositionIndex = 0; - - final TextEditingController _locationController = TextEditingController(); - final List<_Position> _positions = [ - _Position(schedules: [_Schedule(selectedDays: [])]), - ]; - - final List _employmentTypes = ['FULL-TIME', 'PART-TIME', 'CONTRACT']; - final List _days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; - final List _roles = [ - 'Server', - 'Bartender', - 'Cook', - 'Busser', - 'Host', - 'Barista', - 'Dishwasher', - 'Event Staff', - 'Manager', - 'Supervisor' - ]; - - void _addPosition() { - setState(() { - _positions.add(_Position(schedules: [_Schedule(selectedDays: [])])); - _openPositionIndex = _positions.length - 1; - }); - } - - void _removePosition(int index) { - if (_positions.length > 1) { - setState(() { - _positions.removeAt(index); - if (_openPositionIndex >= _positions.length) { - _openPositionIndex = _positions.length - 1; - } - }); - } - } - - void _toggleDay(int posIndex, int scheduleIndex, String day) { - setState(() { - final selectedDays = - _positions[posIndex].schedules[scheduleIndex].selectedDays; - if (selectedDays.contains(day)) { - selectedDays.remove(day); - } else { - selectedDays.add(day); - } - }); - } - - void _addSchedule(int posIndex) { - setState(() { - _positions[posIndex].schedules.add(_Schedule(selectedDays: [])); - }); - } - - void _removeSchedule(int posIndex, int scheduleIndex) { - if (_positions[posIndex].schedules.length > 1) { - setState(() { - _positions[posIndex].schedules.removeAt(scheduleIndex); - }); - } - } - - void _updateScheduleTime( - int posIndex, - int scheduleIndex, - String field, - String time, - ) { - setState(() { - if (field == 'startTime') { - _positions[posIndex].schedules[scheduleIndex].startTime = time; - } else { - _positions[posIndex].schedules[scheduleIndex].endTime = time; - } - }); - } - - @override - Widget build(BuildContext context) { - if (_submitted) { - return const _SuccessView(); - } - - if (_showReview) { - return _buildReviewView(); - } - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - // Header - _buildHeader( - title: 'Permanent Placement', - subtitle: 'Long-term staffing solution', - onBack: () => context.pop(), - color: const Color(0xFF121826), - ), - - // Content - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Location - _buildLabel('Location'), - const SizedBox(height: 8), - _buildTextField( - controller: _locationController, - hint: 'Enter work location', - icon: LucideIcons.mapPin, - ), - const SizedBox(height: 24), - - // Positions - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [_buildLabel('Positions (${_positions.length})')], - ), - const SizedBox(height: 12), - ..._positions.asMap().entries.map((entry) { - return _buildPositionAccordion(entry.key, entry.value); - }), - - const SizedBox(height: 16), - _buildAddButton( - label: 'Add Another Position', - onTap: _addPosition, - dashed: true, - isPrimary: true, - ), - const SizedBox(height: 32), - ], - ), - ), - ), - - // Footer - _buildFooterButton( - label: 'Review Order', - onTap: () => setState(() => _showReview = true), - ), - ], - ), - ); - } - - Widget _buildReviewView() { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - _buildHeader( - title: 'Review Order', - subtitle: 'Confirm details before posting', - onBack: () => setState(() => _showReview = false), - color: const Color(0xFF121826), - ), - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Order Details - _buildSectionTitle('Order Details'), - const SizedBox(height: 12), - _buildReviewCard([ - _buildReviewRow( - 'Location', - _locationController.text.isEmpty - ? 'Not set' - : _locationController.text, - ), - ]), - const SizedBox(height: 24), - - // Positions Summary - _buildSectionTitle('Positions (${_positions.length})'), - const SizedBox(height: 12), - ..._positions.map((pos) => _buildPositionReviewCard(pos)), - const SizedBox(height: 24), - - // Total Summary - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBlue, width: 2), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Total Positions', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - Text( - '${_positions.fold(0, (sum, p) => sum + p.count)}', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '${_positions.length} role${_positions.length > 1 ? 's' : ''}', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - Text( - '${_positions.fold(0, (sum, p) => sum + p.schedules.length)} schedules', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - ), - const SizedBox(height: 32), - ], - ), - ), - ), - _buildFooterButton( - label: 'Confirm & Post', - onTap: () => setState(() => _submitted = true), - ), - ], - ), - ); - } - - // --- UI Helpers --- - - Widget _buildHeader({ - required String title, - required String subtitle, - required VoidCallback onBack, - required Color color, - }) { - return Container( - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 20, - bottom: 20, - left: 20, - right: 20, - ), - color: color, - child: Row( - children: [ - GestureDetector( - onTap: onBack, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 24, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - subtitle, - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.8), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildLabel(String text) { - return Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, // Medium as per React font-medium - color: Color(0xFF475569), // slate-600 - ), - ); - } - - Widget _buildSectionTitle(String text) { - return Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ); - } - - Widget _buildTextField({ - required TextEditingController controller, - required String hint, - required IconData icon, - }) { - return Container( - height: 48, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: TextField( - controller: controller, - decoration: InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Colors.grey, fontSize: 14), - prefixIcon: Icon(icon, size: 20, color: const Color(0xFF94A3B8)), // slate-400 - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric(vertical: 14), - ), - ), - ); - } - - Widget _buildPositionAccordion(int index, _Position pos) { - bool isOpen = _openPositionIndex == index; - return Container( - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - GestureDetector( - onTap: () => - setState(() => _openPositionIndex = isOpen ? -1 : index), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - color: Colors.transparent, - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - pos.role.isEmpty ? 'Position ${index + 1}' : pos.role, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - if (pos.role.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Row( - children: [ - const Icon(LucideIcons.users, size: 12, color: AppColors.krowMuted), - const SizedBox(width: 4), - Text('${pos.count}', style: const TextStyle(fontSize: 12, color: AppColors.krowMuted)), - if (pos.employmentType.isNotEmpty) ...[ - const SizedBox(width: 8), - Text(pos.employmentType, style: const TextStyle(fontSize: 12, color: AppColors.krowMuted)), - ], - const SizedBox(width: 8), - const Icon(LucideIcons.clock, size: 12, color: AppColors.krowMuted), - const SizedBox(width: 4), - Text('${pos.schedules.length} schedule${pos.schedules.length > 1 ? 's' : ''}', style: const TextStyle(fontSize: 12, color: AppColors.krowMuted)), - ], - ), - ), - ], - ), - ), - Icon( - isOpen ? LucideIcons.chevronUp : LucideIcons.chevronDown, - size: 20, - color: AppColors.krowMuted, - ), - ], - ), - ), - ), - if (isOpen) - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Divider(height: 1, color: AppColors.krowBorder), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Position ${index + 1}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowMuted, - ), - ), - if (_positions.length > 1) - GestureDetector( - onTap: () => _removePosition(index), - child: const Text( - 'Remove', - style: TextStyle(fontSize: 12, color: Colors.red), - ), - ), - ], - ), - const SizedBox(height: 12), - // Role - _buildDropdown( - hint: 'Select role', - value: pos.role.isEmpty ? null : pos.role, - items: _roles, - onChanged: (val) => setState(() => pos.role = val ?? ''), - ), - const SizedBox(height: 16), - // Employment Type - const Text( - 'Employment Type', - style: TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - const SizedBox(height: 4), - Row( - children: _employmentTypes.map((type) { - final isSelected = pos.employmentType == type; - return Expanded( - child: GestureDetector( - onTap: () => - setState(() => pos.employmentType = type), - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 4), - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue - : Colors.white, - borderRadius: BorderRadius.circular(6), - border: Border.all( - color: isSelected - ? AppColors.krowBlue - : AppColors.krowBorder, - ), - ), - alignment: Alignment.center, - child: Text( - type, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : AppColors.krowCharcoal, - ), - ), - ), - ), - ); - }).toList(), - ), - const SizedBox(height: 16), - // Count & Salary (Positions / Salary Range) - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Positions', style: TextStyle(fontSize: 12, color: Color(0xFF64748B))), - const SizedBox(height: 4), - Row( - children: [ - _buildCounterButton(LucideIcons.minus, () => setState(() => pos.count = (pos.count > 1) ? pos.count - 1 : 1)), - Expanded( - child: Container( - height: 40, - alignment: Alignment.center, - decoration: const BoxDecoration( - border: Border.symmetric(vertical: BorderSide.none, horizontal: BorderSide(color: AppColors.krowBorder)), - ), - child: Text('${pos.count}', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - ), - ), - _buildCounterButton(LucideIcons.plus, () => setState(() => pos.count++)), - ], - ), - ], - ), - ), - const SizedBox(width: 12), - Expanded( - flex: 2, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Salary Range (Annual)', style: TextStyle(fontSize: 12, color: Color(0xFF64748B))), - const SizedBox(height: 4), - Row( - children: [ - Expanded( - child: _buildSmallTextField( - hint: 'Min', - value: pos.salaryMin == 0 ? '' : pos.salaryMin.toStringAsFixed(0), - onChanged: (v) => pos.salaryMin = double.tryParse(v) ?? 0, - ), - ), - const Padding(padding: EdgeInsets.symmetric(horizontal: 4), child: Text('-')), - Expanded( - child: _buildSmallTextField( - hint: 'Max', - value: pos.salaryMax == 0 ? '' : pos.salaryMax.toStringAsFixed(0), - onChanged: (v) => pos.salaryMax = double.tryParse(v) ?? 0, - ), - ), - ], - ), - ], - ), - ), - ], - ), - const SizedBox(height: 16), - // Description - const Text( - 'Description', - style: TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - const SizedBox(height: 4), - _buildLargeTextField( - hint: 'Tell candidates about the role...', - onChanged: (v) => pos.description = v, - ), - const SizedBox(height: 16), - // Requirements - const Text( - 'Requirements', - style: TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - const SizedBox(height: 4), - _buildLargeTextField( - hint: 'Skills, experience, certificates...', - onChanged: (v) => pos.requirements = v, - ), - const SizedBox(height: 20), - const Text( - 'Schedules', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF475569), - ), - ), - const SizedBox(height: 8), - ...pos.schedules.asMap().entries.map((sEntry) { - final sIdx = sEntry.key; - final schedule = sEntry.value; - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), // slate-50 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Schedule ${sIdx + 1}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowMuted, - ), - ), - if (pos.schedules.length > 1) - GestureDetector( - onTap: () => _removeSchedule(index, sIdx), - child: const Text('Remove', style: TextStyle(fontSize: 10, color: Colors.red)), - ), - ], - ), - const SizedBox(height: 12), - Row( - children: _days.map((day) { - final isSelected = schedule.selectedDays.contains( - day, - ); - return Expanded( - child: GestureDetector( - onTap: () => _toggleDay(index, sIdx, day), - child: Container( - margin: const EdgeInsets.symmetric( - horizontal: 2, - ), - padding: const EdgeInsets.symmetric( - vertical: 8, - ), - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue - : Colors.white, - borderRadius: BorderRadius.circular(6), - ), - alignment: Alignment.center, - child: Text( - day, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : AppColors.krowMuted, - ), - ), - ), - ), - ); - }).toList(), - ), - const SizedBox(height: 12), - Row( - children: [ - Expanded( - child: _buildTimeInput( - hint: 'Start', - value: schedule.startTime, - onTap: () async { - final picked = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (picked != null) - _updateScheduleTime( - index, - sIdx, - 'startTime', - picked.format(context), - ); - }, - ), - ), - const SizedBox(width: 8), - Expanded( - child: _buildTimeInput( - hint: 'End', - value: schedule.endTime, - onTap: () async { - final picked = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (picked != null) - _updateScheduleTime( - index, - sIdx, - 'endTime', - picked.format(context), - ); - }, - ), - ), - ], - ), - ], - ), - ); - }), - _buildAddButton( - label: 'Add Another Schedule', - onTap: () => _addSchedule(index), - dashed: false, - isPrimary: false, - small: true, - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildDropdown({ - required String hint, - required String? value, - required List items, - required Function(String?) onChanged, - }) { - return Container( - height: 44, // h-11 - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - isExpanded: true, - hint: Text(hint, style: const TextStyle(fontSize: 14)), - value: value, - onChanged: (v) => onChanged(v), - items: items - .map( - (r) => DropdownMenuItem( - value: r, - child: Text(r, style: const TextStyle(fontSize: 14)), - ), - ) - .toList(), - ), - ), - ); - } - - Widget _buildSmallTextField({ - required String hint, - required String value, - required Function(String) onChanged, - }) { - return Container( - height: 40, // h-10 - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: TextField( - keyboardType: TextInputType.number, - style: const TextStyle(fontSize: 13), - decoration: InputDecoration( - border: InputBorder.none, - hintText: hint, - prefixText: ' \$ ', // Space for spacing - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 10, // Center vertically - ), - ), - onChanged: onChanged, - controller: TextEditingController(text: value), - ), - ); - } - - Widget _buildLargeTextField({ - required String hint, - required Function(String) onChanged, - }) { - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: TextField( - minLines: 3, - maxLines: null, - style: const TextStyle(fontSize: 13), - decoration: InputDecoration( - border: InputBorder.none, - hintText: hint, - hintStyle: const TextStyle(color: Colors.grey, fontSize: 13), - contentPadding: const EdgeInsets.all(12), - ), - onChanged: onChanged, - ), - ); - } - - Widget _buildReviewRow(String label, String value) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: const TextStyle(fontSize: 14, color: AppColors.krowMuted), - ), - Text( - value, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } - - Widget _buildReviewCard(List children) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - child: Column(children: children), - ); - } - - Widget _buildPositionReviewCard(_Position pos) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - pos.role.isEmpty ? 'Unspecified Role' : pos.role, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(top: 4), - child: Row( - children: [ - Text( - '${pos.count} position${pos.count > 1 ? 's' : ''}', - style: const TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - const SizedBox(width: 12), - if (pos.employmentType.isNotEmpty) ...[ - Text(pos.employmentType, style: const TextStyle(fontSize: 12, color: AppColors.krowMuted)), - const SizedBox(width: 12), - ], - Text( - '\$${pos.salaryMin ~/ 1000}k - \$${pos.salaryMax ~/ 1000}k', - style: const TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ], - ), - ), - if (pos.description.isNotEmpty) ...[ - const SizedBox(height: 8), - Text(pos.description, style: const TextStyle(fontSize: 12, color: AppColors.krowMuted), maxLines: 2, overflow: TextOverflow.ellipsis), - ], - if (pos.schedules.isNotEmpty) ...[ - const SizedBox(height: 12), - ...pos.schedules.map( - (sche) => Container( - margin: const EdgeInsets.only(bottom: 6), - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), // slate-50 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Schedule 1', // Simplified for mock - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - '${sche.selectedDays.isNotEmpty ? sche.selectedDays.join(', ') : 'No days'}: ${sche.startTime.isNotEmpty ? sche.startTime : '--'} - ${sche.endTime.isNotEmpty ? sche.endTime : '--'}', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - ), - ], - ], - ), - ); - } - - Widget _buildAddButton({required String label, required VoidCallback onTap, bool dashed = false, bool isPrimary = true, bool small = false}) { - return GestureDetector( - onTap: onTap, - child: Container( - width: double.infinity, - height: small ? 36 : 44, // h-9 or h-11 - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: isPrimary ? AppColors.krowBlue : AppColors.krowBorder, - width: isPrimary && dashed ? 2 : 1, - style: BorderStyle.solid, // Use custom painter for real dash if needed, solid for now - ), - color: isPrimary ? Colors.white : Colors.transparent, - ), - child: Center( - child: Text( - '+ $label', - style: TextStyle( - color: isPrimary ? AppColors.krowBlue : AppColors.krowMuted, - fontWeight: isPrimary ? FontWeight.bold : FontWeight.w500, - fontSize: small ? 12 : 14, - ), - ), - ), - ), - ); - } - - Widget _buildTimeInput({ - required String hint, - required String value, - required VoidCallback onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - height: 40, - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - alignment: Alignment.centerLeft, - child: Text( - value.isEmpty ? hint : value, - style: TextStyle( - fontSize: 12, - color: value.isEmpty ? Colors.grey : AppColors.krowCharcoal, - ), - ), - ), - ); - } - - Widget _buildCounterButton(IconData icon, VoidCallback onTap) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 36, // w-9 - height: 40, // h-10 - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - color: Colors.white, - ), - child: Icon(icon, size: 16, color: AppColors.krowMuted), - ), - ); - } - - Widget _buildAddSmallButton({ - required String label, - required VoidCallback onTap, - }) { - return _buildAddButton(label: label, onTap: onTap, dashed: false, isPrimary: false, small: true); - } - - Widget _buildFooterButton({ - required String label, - required VoidCallback onTap, - }) { - return Container( - padding: EdgeInsets.only( - left: 20, - right: 20, - top: 20, - bottom: MediaQuery.of(context).padding.bottom + 20, - ), - color: Colors.white, - child: SizedBox( - width: double.infinity, - height: 48, // h-12 - child: ElevatedButton( - onPressed: onTap, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), // rounded-md - ), - elevation: 0, - ), - child: Text( - label, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ), - ), - ); - } -} - -class _SuccessView extends StatelessWidget { - const _SuccessView(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Color(0xFF2D3748), Color(0xFF1A202C)], // slate-800 to slate-900 - ), - ), - child: SafeArea( - child: Center( - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 40), - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), // rounded-lg - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: AppColors.krowYellow, - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.check, - color: AppColors.krowCharcoal, - size: 32, - ), - ), - ), - const SizedBox(height: 24), - const Text( - 'Position Posted!', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 12), - const Text( - 'Your permanent position has been posted. We\'ll match qualified candidates for you.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - height: 1.5, - ), - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () => context.go('/client-home'), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowCharcoal, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), // rounded-md - ), - elevation: 0, - ), - child: const Text( - 'Back to Orders', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} - diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/rapid_order_flow_page.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/rapid_order_flow_page.dart deleted file mode 100644 index 87e57bd5..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/rapid_order_flow_page.dart +++ /dev/null @@ -1,530 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../../theme.dart'; - -class RapidOrderFlowPage extends StatefulWidget { - const RapidOrderFlowPage({super.key}); - - @override - State createState() => _RapidOrderFlowPageState(); -} - -class _RapidOrderFlowPageState extends State { - final TextEditingController _messageController = TextEditingController(); - bool _isListening = false; - bool _submitted = false; - bool _isSending = false; - - final List _examples = [ - '"We had a call out. Need 2 cooks ASAP"', - '"Need 5 bartenders ASAP until 5am"', - '"Emergency! Need 3 servers right now till midnight"', - ]; - - Future _handleSubmit() async { - if (_messageController.text.trim().isEmpty) return; - - setState(() { - _isSending = true; - }); - - // Simulate API call - await Future.delayed(const Duration(seconds: 1)); - - if (mounted) { - setState(() { - _isSending = false; - _submitted = true; - }); - } - } - - void _handleSpeak() { - setState(() { - _isListening = !_isListening; - }); - // Mock speech recognition - if (_isListening) { - Future.delayed(const Duration(seconds: 2), () { - if (mounted) { - setState(() { - _messageController.text = "Need 2 servers for a banquet right now."; - _isListening = false; - }); - } - }); - } - } - - @override - Widget build(BuildContext context) { - if (_submitted) { - return const _SuccessView(); - } - - final now = DateTime.now(); - final dateStr = DateFormat('EEE, MMM dd, yyyy').format(now); - final timeStr = DateFormat('h:mm a').format(now); - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - // Header - Container( - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 20, - bottom: 20, - left: 20, - right: 20, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFFF04444), Color(0xFFD63939)], - begin: Alignment.centerLeft, - end: Alignment.centerRight, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 24, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.zap, - color: AppColors.krowYellow, - size: 18, - ), - const SizedBox(width: 6), - const Text( - 'RAPID Order', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - Text( - 'Emergency staffing in minutes', - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.8), - ), - ), - ], - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - dateStr, - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.9), - ), - ), - Text( - timeStr, - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.9), - ), - ), - ], - ), - ], - ), - ), - - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Tell us what you need', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 4, - ), - decoration: BoxDecoration( - color: const Color(0xFFF04444), - borderRadius: BorderRadius.circular(6), - ), - child: const Text( - 'URGENT', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ], - ), - const SizedBox(height: 16), - - // Main Card - Container( - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFF04444), Color(0xFFD63939)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: const Color(0xFFF04444).withOpacity(0.3), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: const Icon( - LucideIcons.zap, - color: Colors.white, - size: 32, - ), - ), - const SizedBox(height: 16), - const Text( - 'Need staff urgently?', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 6), - const Text( - 'Type or speak what you need. I\'ll handle the rest', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 24), - - // Examples - ..._examples.asMap().entries.map((entry) { - final index = entry.key; - final example = entry.value; - final isFirst = index == 0; - return Padding( - padding: const EdgeInsets.only(bottom: 10), - child: GestureDetector( - onTap: () { - setState(() { - _messageController.text = example.replaceAll( - '"', - '', - ); - }); - }, - child: Container( - width: double.infinity, - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 14, - ), - decoration: BoxDecoration( - color: isFirst - ? AppColors.krowYellow.withOpacity(0.15) - : Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: isFirst - ? AppColors.krowYellow - : AppColors.krowBorder, - ), - ), - child: RichText( - text: TextSpan( - style: const TextStyle( - color: AppColors.krowCharcoal, - fontSize: 14, - ), - children: [ - const TextSpan( - text: 'Example: ', - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - TextSpan(text: example), - ], - ), - ), - ), - ), - ); - }), - const SizedBox(height: 16), - - // Input - TextField( - controller: _messageController, - maxLines: 4, - decoration: InputDecoration( - hintText: - 'Type or speak... (e.g., "Need 5 cooks ASAP until 5am")', - hintStyle: const TextStyle( - color: Colors.grey, - fontSize: 14, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide( - color: AppColors.krowBorder, - ), - ), - contentPadding: const EdgeInsets.all(16), - ), - ), - const SizedBox(height: 16), - - // Actions - Row( - children: [ - Expanded( - child: SizedBox( - height: 52, - child: OutlinedButton.icon( - onPressed: _handleSpeak, - icon: Icon( - LucideIcons.mic, - size: 20, - color: _isListening - ? Colors.red - : AppColors.krowCharcoal, - ), - label: Text( - _isListening ? 'Listening...' : 'Speak', - style: TextStyle( - color: _isListening - ? Colors.red - : AppColors.krowCharcoal, - fontWeight: FontWeight.w600, - ), - ), - style: OutlinedButton.styleFrom( - backgroundColor: _isListening - ? Colors.red.withOpacity(0.05) - : Colors.white, - side: BorderSide( - color: _isListening - ? Colors.red - : AppColors.krowBorder, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: SizedBox( - height: 52, - child: ElevatedButton.icon( - onPressed: - _isSending || - _messageController.text.trim().isEmpty - ? null - : _handleSubmit, - icon: const Icon( - LucideIcons.send, - size: 20, - color: Colors.white, - ), - label: Text( - _isSending ? 'Sending...' : 'Send Message', - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - ), - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ), - ], - ), - ); - } -} - -class _SuccessView extends StatelessWidget { - const _SuccessView(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [AppColors.krowBlue, Color(0xFF0830B8)], - ), - ), - child: SafeArea( - child: Center( - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 40), - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: AppColors.krowYellow, - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.zap, - color: AppColors.krowCharcoal, - size: 32, - ), - ), - ), - const SizedBox(height: 24), - const Text( - 'Request Sent!', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 12), - const Text( - 'We\'re finding available workers for you right now. You\'ll be notified as they accept.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - height: 1.5, - ), - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 52, - child: ElevatedButton( - onPressed: () => context.pop(), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowCharcoal, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: const Text( - 'Back to Orders', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/recurring_order_flow_page.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/recurring_order_flow_page.dart deleted file mode 100644 index caca4114..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_pages/recurring_order_flow_page.dart +++ /dev/null @@ -1,1352 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../../theme.dart'; - -class RecurringOrderFlowPage extends StatefulWidget { - const RecurringOrderFlowPage({super.key}); - - @override - State createState() => _RecurringOrderFlowPageState(); -} - -class _Schedule { - List selectedDays; - String startTime; - String endTime; - - _Schedule({ - required this.selectedDays, - this.startTime = '', - this.endTime = '', - }); - - _Schedule copy() => _Schedule( - selectedDays: List.from(selectedDays), - startTime: startTime, - endTime: endTime, - ); -} - -class _Position { - String role; - int count; - double rate; - List<_Schedule> schedules; - - _Position({ - this.role = '', - this.count = 1, - this.rate = 20, - required this.schedules, - }); - - _Position copy() => _Position( - role: role, - count: count, - rate: rate, - schedules: schedules.map((s) => s.copy()).toList(), - ); -} - -class _RecurringOrderFlowPageState extends State { - bool _submitted = false; - bool _showReview = false; - int _openPositionIndex = 0; - - final TextEditingController _locationController = TextEditingController(); - String _duration = 'weekly'; - int _lunchBreak = 30; - String _startDate = ''; - String _endDate = ''; - - final List<_Position> _positions = [ - _Position(schedules: [_Schedule(selectedDays: [])]), - ]; - - final List _days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; - final List _roles = [ - 'Server', - 'Bartender', - 'Cook', - 'Busser', - 'Host', - 'Barista', - 'Dishwasher', - 'Event Staff', - ]; - - double _calculateTotalCost() { - double total = 0; - for (var pos in _positions) { - for (var schedule in pos.schedules) { - if (schedule.startTime.isNotEmpty && - schedule.endTime.isNotEmpty && - schedule.selectedDays.isNotEmpty) { - try { - // Very basic estimation for mock: start/end times difference - // In a real app, use DateFormat or TimeOfDay logic more robustly - // Here assuming standard inputs or just returning a mock cost if calculation fails - // to prevent crashes. React code does precise math, let's approximate or try-catch. - // Simplified logic: assume 8 hours per shift for mock visuals if empty - // But let's try to parse: - - // Note: input format from TimePicker is usually "h:mm AM/PM" or "HH:mm" depending on locale - // React uses "HH:mm" input type="time". Flutter TimePicker returns formatted string. - // We'll trust the user input or default to 0. - - // For MVP, if we can't parse, we ignore. - total += - 8 * - pos.rate * - pos.count * - schedule.selectedDays.length * - (_duration == 'weekly' ? 1 : 4); - } catch (e) { - // ignore - } - } - } - } - // Return a non-zero mock value if everything is empty for better visual - if (total == 0) return 1200.00; - return total; - } - - void _addPosition() { - setState(() { - _positions.add(_Position(schedules: [_Schedule(selectedDays: [])])); - _openPositionIndex = _positions.length - 1; - }); - } - - void _removePosition(int index) { - if (_positions.length > 1) { - setState(() { - _positions.removeAt(index); - if (_openPositionIndex >= _positions.length) { - _openPositionIndex = _positions.length - 1; - } - }); - } - } - - void _addSchedule(int posIndex) { - setState(() { - _positions[posIndex].schedules.add(_Schedule(selectedDays: [])); - }); - } - - void _removeSchedule(int posIndex, int scheduleIndex) { - if (_positions[posIndex].schedules.length > 1) { - setState(() { - _positions[posIndex].schedules.removeAt(scheduleIndex); - }); - } - } - - void _toggleDay(int posIndex, int scheduleIndex, String day) { - setState(() { - final selectedDays = - _positions[posIndex].schedules[scheduleIndex].selectedDays; - if (selectedDays.contains(day)) { - selectedDays.remove(day); - } else { - selectedDays.add(day); - } - }); - } - - @override - Widget build(BuildContext context) { - if (_submitted) { - return const _SuccessView(); - } - - if (_showReview) { - return _buildReviewView(); - } - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - // Header - _buildHeader( - title: 'Recurring Order', - subtitle: 'Ongoing weekly/monthly coverage', - onBack: () => context.pop(), - color: const Color(0xFF121826), // Match React foreground color - ), - - // Content - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Location - _buildLabel('Location'), - const SizedBox(height: 8), - _buildTextField( - controller: _locationController, - hint: 'Enter address', - icon: null, // React input doesn't show icon - ), - const SizedBox(height: 24), - - // Duration - _buildLabel('Duration'), - const SizedBox(height: 8), - Row( - children: ['weekly', 'monthly'].map((d) { - final isSelected = _duration == d; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _duration = d), - child: Container( - margin: EdgeInsets.only( - right: d == 'weekly' ? 12 : 0, - ), - padding: const EdgeInsets.symmetric(vertical: 14), - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue - : Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: isSelected - ? AppColors.krowBlue - : AppColors.krowBorder, - ), - ), - alignment: Alignment.center, - child: Text( - d[0].toUpperCase() + d.substring(1), - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : AppColors.krowCharcoal, - ), - ), - ), - ), - ); - }).toList(), - ), - const SizedBox(height: 24), - - // Dates - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildLabel('Start Date'), - const SizedBox(height: 8), - _buildDateField( - value: _startDate, - onTap: () async { - final picked = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime.now(), - lastDate: DateTime.now().add( - const Duration(days: 365), - ), - ); - if (picked != null) { - setState( - () => _startDate = DateFormat( - 'yyyy-MM-dd', - ).format(picked), - ); - } - }, - ), - ], - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildLabel('End Date (Optional)'), - const SizedBox(height: 8), - _buildDateField( - value: _endDate, - onTap: () async { - final picked = await showDatePicker( - context: context, - initialDate: DateTime.now().add( - const Duration(days: 7), - ), - firstDate: DateTime.now(), - lastDate: DateTime.now().add( - const Duration(days: 730), - ), - ); - if (picked != null) { - setState( - () => _endDate = DateFormat( - 'yyyy-MM-dd', - ).format(picked), - ); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 24), - - // Lunch Break - _buildLabel('Lunch Break'), - const SizedBox(height: 8), - _buildLunchBreakDropdown(), - const SizedBox(height: 24), - - // Positions - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [_buildLabel('Positions (${_positions.length})')], - ), - const SizedBox(height: 12), - ..._positions.asMap().entries.map((entry) { - return _buildPositionAccordion(entry.key, entry.value); - }), - - const SizedBox(height: 16), - _buildAddButton( - label: 'Add Another Position', - onTap: _addPosition, - dashed: true, - isPrimary: true, - ), - const SizedBox(height: 32), - ], - ), - ), - ), - - // Footer - _buildFooterButton( - label: 'Review Order', - onTap: () => setState(() => _showReview = true), - ), - ], - ), - ); - } - - Widget _buildReviewView() { - final totalCost = _calculateTotalCost(); - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - _buildHeader( - title: 'Review Order', - subtitle: 'Confirm details before submitting', - onBack: () => setState(() => _showReview = false), - color: const Color(0xFF121826), - ), - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Order Details Card - _buildSectionTitle('Order Details'), - const SizedBox(height: 12), - _buildReviewCard([ - _buildReviewRow( - 'Location', - _locationController.text.isEmpty - ? 'Not set' - : _locationController.text, - ), - _buildReviewRow( - 'Duration', - _duration[0].toUpperCase() + _duration.substring(1), - ), - _buildReviewRow( - 'Lunch Break', - _lunchBreak == 0 ? 'No break' : '$_lunchBreak min', - ), - _buildReviewRow( - 'Start Date', - _startDate.isEmpty ? 'Not set' : _startDate, - ), - if (_endDate.isNotEmpty) - _buildReviewRow('End Date', _endDate), - ]), - const SizedBox(height: 24), - - // Positions Summary - _buildSectionTitle('Positions (${_positions.length})'), - const SizedBox(height: 12), - ..._positions.map((pos) => _buildPositionReviewCard(pos)), - - const SizedBox(height: 24), - - // Total Cost Card - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBlue, width: 2), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Estimated $_duration cost', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 4), - Text( - '\$${totalCost.toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '${_positions.fold(0, (sum, p) => sum + p.count)} total workers', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - Text( - '${_positions.fold(0, (sum, p) => sum + p.schedules.length)} schedules', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - ), - const SizedBox(height: 32), - ], - ), - ), - ), - _buildFooterButton( - label: 'Confirm & Submit', - onTap: () => setState(() => _submitted = true), - ), - ], - ), - ); - } - - // --- UI Helpers --- - - Widget _buildHeader({ - required String title, - required String subtitle, - required VoidCallback onBack, - Color color = AppColors.krowBlue, - }) { - return Container( - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 20, - bottom: 20, - left: 20, - right: 20, - ), - color: color, - child: Row( - children: [ - GestureDetector( - onTap: onBack, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(10), - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 24, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - subtitle, - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.8), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildLabel(String text) { - return Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, // Medium as per React - color: Color(0xFF475569), // slate-600 - ), - ); - } - - Widget _buildSectionTitle(String text) { - return Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ); - } - - Widget _buildTextField({ - required TextEditingController controller, - required String hint, - IconData? icon, - }) { - return Container( - height: 48, // React input h-12 (48px) - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - padding: EdgeInsets.only(left: icon != null ? 0 : 16), - child: TextField( - controller: controller, - decoration: InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Colors.grey, fontSize: 14), - prefixIcon: icon != null - ? Icon(icon, size: 20, color: AppColors.krowMuted) - : null, - border: InputBorder.none, - contentPadding: const EdgeInsets.symmetric( - vertical: 14, - ), // Centered vertically - ), - ), - ); - } - - Widget _buildDateField({required String value, required VoidCallback onTap}) { - return GestureDetector( - onTap: onTap, - child: Container( - height: 48, - padding: const EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Row( - children: [ - if (value.isEmpty) ...[ - // No icon in React input type=date typically unless customized, but looks like standard input - // Keeping it simpler - ], - Expanded( - child: Text( - value.isEmpty ? 'mm/dd/yyyy' : value, // Placeholder style - style: TextStyle( - color: value.isEmpty ? Colors.grey : AppColors.krowCharcoal, - fontSize: 14, - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildLunchBreakDropdown() { - return Container( - height: 48, - padding: const EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - value: _lunchBreak, - isExpanded: true, - icon: const Icon(LucideIcons.chevronDown, size: 20), - onChanged: (val) => setState(() => _lunchBreak = val ?? 30), - items: [ - const DropdownMenuItem(value: 0, child: Text('No break')), - const DropdownMenuItem(value: 10, child: Text('10 min (Paid)')), - const DropdownMenuItem(value: 15, child: Text('15 min (Paid)')), - const DropdownMenuItem(value: 30, child: Text('30 min (Unpaid)')), - const DropdownMenuItem(value: 45, child: Text('45 min (Unpaid)')), - const DropdownMenuItem(value: 60, child: Text('60 min (Unpaid)')), - ], - ), - ), - ); - } - - Widget _buildPositionAccordion(int index, _Position pos) { - bool isOpen = _openPositionIndex == index; - return Container( - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - GestureDetector( - onTap: () => - setState(() => _openPositionIndex = isOpen ? -1 : index), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - color: Colors.transparent, - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - pos.role.isEmpty ? 'Position ${index + 1}' : pos.role, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - if (pos.role.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Row( - children: [ - _buildBadge(LucideIcons.users, '${pos.count}'), - const SizedBox(width: 8), - _buildBadge( - LucideIcons.dollarSign, - '${pos.rate}/hr', - ), - const SizedBox(width: 8), - _buildBadge( - LucideIcons.clock, - '${pos.schedules.length} schedule${pos.schedules.length > 1 ? 's' : ''}', - ), - ], - ), - ), - ], - ), - ), - Icon( - isOpen ? LucideIcons.chevronUp : LucideIcons.chevronDown, - size: 20, - color: AppColors.krowMuted, - ), - ], - ), - ), - ), - if (isOpen) - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Divider(height: 1, color: AppColors.krowBorder), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Position ${index + 1}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowMuted, - ), - ), - if (_positions.length > 1) - GestureDetector( - onTap: () => _removePosition(index), - child: const Text( - 'Remove', - style: TextStyle(fontSize: 12, color: Colors.red), - ), - ), - ], - ), - const SizedBox(height: 12), - // Role - Container( - height: 44, // h-11 - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - isExpanded: true, - icon: const Icon( - LucideIcons.chevronDown, - size: 20, - color: AppColors.krowMuted, - ), - hint: const Text( - 'Select role', - style: TextStyle(fontSize: 14), - ), - value: pos.role.isEmpty ? null : pos.role, - onChanged: (val) => - setState(() => pos.role = val ?? ''), - items: _roles - .map( - (r) => DropdownMenuItem(value: r, child: Text(r)), - ) - .toList(), - ), - ), - ), - const SizedBox(height: 12), - // Count & Rate - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Workers', - style: TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - const SizedBox(height: 4), - Row( - children: [ - _buildCounterButton( - LucideIcons.minus, - () => setState( - () => pos.count = (pos.count > 1) - ? pos.count - 1 - : 1, - ), - ), - Expanded( - child: Container( - height: 44, - alignment: Alignment.center, - decoration: const BoxDecoration( - border: Border.symmetric( - vertical: BorderSide.none, - horizontal: BorderSide( - color: AppColors.krowBorder, - ), - ), - ), - child: Text( - '${pos.count}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - ), - _buildCounterButton( - LucideIcons.plus, - () => setState(() => pos.count++), - ), - ], - ), - ], - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Rate/hr', - style: TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - ), - const SizedBox(height: 4), - Container( - height: 44, - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: TextField( - keyboardType: TextInputType.number, - textAlign: TextAlign.left, - style: const TextStyle(fontSize: 14), - decoration: const InputDecoration( - border: InputBorder.none, - isDense: true, - contentPadding: EdgeInsets.symmetric( - horizontal: 12, - ), - ), - onChanged: (val) => - pos.rate = double.tryParse(val) ?? 20.0, - controller: TextEditingController( - text: pos.rate.toStringAsFixed(0), - ), - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 20), - const Text( - 'Schedules', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF475569), - ), - ), - const SizedBox(height: 12), - ...pos.schedules.asMap().entries.map((scheEntry) { - return _buildScheduleItem( - index, - scheEntry.key, - scheEntry.value, - ); - }), - _buildAddButton( - label: 'Add Another Schedule', - onTap: () => _addSchedule(index), - dashed: false, - isPrimary: false, // Outline button - small: true, - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildBadge(IconData icon, String text) { - return Row( - children: [ - Icon(icon, size: 12, color: AppColors.krowMuted), - const SizedBox(width: 4), - Text( - text, - style: const TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ], - ); - } - - Widget _buildCounterButton(IconData icon, VoidCallback onTap) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 40, - height: 44, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - color: Colors.white, - ), - child: Icon(icon, size: 16, color: AppColors.krowMuted), - ), - ); - } - - Widget _buildScheduleItem(int posIndex, int scheIndex, _Schedule sche) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), // slate-50 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Schedule ${scheIndex + 1}', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowMuted, - ), - ), - if (_positions[posIndex].schedules.length > 1) - GestureDetector( - onTap: () => _removeSchedule(posIndex, scheIndex), - child: const Text( - 'Remove', - style: TextStyle(fontSize: 10, color: Colors.red), - ), - ), - ], - ), - const SizedBox(height: 12), - // Days - Row( - children: _days.map((day) { - final isSelected = sche.selectedDays.contains(day); - return Expanded( - child: GestureDetector( - onTap: () => _toggleDay(posIndex, scheIndex, day), - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 2), - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected ? AppColors.krowBlue : Colors.white, - borderRadius: BorderRadius.circular(6), - ), - alignment: Alignment.center, - child: Text( - day, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: isSelected ? Colors.white : AppColors.krowMuted, - ), - ), - ), - ), - ); - }).toList(), - ), - const SizedBox(height: 12), - // Times - Row( - children: [ - Expanded( - child: _buildTimeInput( - value: sche.startTime, - hint: 'Start', - onTap: () async { - final time = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (time != null) - setState(() => sche.startTime = time.format(context)); - }, - ), - ), - const SizedBox(width: 8), - Expanded( - child: _buildTimeInput( - value: sche.endTime, - hint: 'End', - onTap: () async { - final time = await showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ); - if (time != null) - setState(() => sche.endTime = time.format(context)); - }, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildTimeInput({ - required String value, - required String hint, - required VoidCallback onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - height: 40, - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - alignment: Alignment.centerLeft, - child: Text( - value.isEmpty ? hint : value, - style: TextStyle( - fontSize: 12, - color: value.isEmpty ? Colors.grey : AppColors.krowCharcoal, - ), - ), - ), - ); - } - - Widget _buildReviewRow(String label, String value) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: const TextStyle(fontSize: 14, color: AppColors.krowMuted), - ), - Text( - value, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } - - Widget _buildReviewCard(List children) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - child: Column(children: children), - ); - } - - Widget _buildPositionReviewCard(_Position pos) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), // rounded-xl - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - pos.role.isEmpty ? 'Unspecified Role' : pos.role, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(top: 4), - child: Row( - children: [ - Text( - '${pos.count} worker${pos.count > 1 ? 's' : ''}', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 12), - Text( - '\$${pos.rate}/hr', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - const SizedBox(height: 12), - ...pos.schedules.map( - (sche) => Container( - margin: const EdgeInsets.only(bottom: 6), - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), // slate-50 - borderRadius: BorderRadius.circular(8), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - sche.selectedDays.isNotEmpty - ? sche.selectedDays.join(', ') - : 'No days selected', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - (sche.startTime.isNotEmpty || sche.endTime.isNotEmpty) - ? '${sche.startTime} - ${sche.endTime}' - : 'Time not set', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildAddButton({ - required String label, - required VoidCallback onTap, - bool dashed = false, - bool isPrimary = true, - bool small = false, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - width: double.infinity, - height: small ? 36 : 44, // h-9 or h-11 - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: isPrimary ? AppColors.krowBlue : AppColors.krowBorder, - width: isPrimary && dashed ? 2 : 1, - style: dashed - ? BorderStyle.solid - : BorderStyle - .solid, // Flutter doesn't support dashed native easily without package, sticking to solid per instruction or using custom painter. - // NOTE: React used `border-dashed`. Without external package, solid is standard fallback. - ), - color: isPrimary ? Colors.white : Colors.transparent, - ), - child: Center( - child: Text( - '+ $label', - style: TextStyle( - color: isPrimary ? AppColors.krowBlue : AppColors.krowMuted, - fontWeight: isPrimary ? FontWeight.bold : FontWeight.w500, - fontSize: small ? 12 : 14, - ), - ), - ), - ), - ); - } - - Widget _buildFooterButton({ - required String label, - required VoidCallback onTap, - }) { - return Container( - padding: EdgeInsets.only( - left: 20, - right: 20, - top: 20, - bottom: MediaQuery.of(context).padding.bottom + 20, - ), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowBorder)), - ), - child: SizedBox( - width: double.infinity, - height: 48, // h-12 - child: ElevatedButton( - onPressed: onTap, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), // rounded-md - ), - elevation: 0, - ), - child: Text( - label, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ), - ), - ); - } -} - -class _SuccessView extends StatelessWidget { - const _SuccessView(); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [AppColors.krowBlue, Color(0xFF0830B8)], - ), - ), - child: SafeArea( - child: Center( - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 40), - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), // rounded-lg - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: AppColors.krowYellow, - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.check, - color: AppColors.krowCharcoal, - size: 32, - ), - ), - ), - const SizedBox(height: 16), - const Text( - 'Schedule Created!', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - 'Your recurring schedule has been set up. Workers will be auto-assigned weekly.', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - height: 1.5, - ), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () => context.go('/client-home'), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowCharcoal, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(6), // rounded-md - ), - elevation: 0, - ), - child: const Text( - 'Back to Orders', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_screen.dart deleted file mode 100644 index 9a4b31b2..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/create_order_screen.dart +++ /dev/null @@ -1,242 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class CreateOrderScreen extends StatefulWidget { - const CreateOrderScreen({super.key}); - - @override - State createState() => _CreateOrderScreenState(); -} - -class _CreateOrderScreenState extends State { - final List> _orderTypes = [ - { - 'id': 'rapid', - 'icon': LucideIcons.zap, - 'title': 'RAPID', - 'description': 'URGENT same-day Coverage', - }, - { - 'id': 'one-time', - 'icon': LucideIcons.calendar, - 'title': 'One-Time', - 'description': 'Single Event or Shift Request', - }, - { - 'id': 'recurring', - 'icon': LucideIcons.refreshCw, - 'title': 'Recurring', - 'description': 'Ongoing Weekly / Monthly Coverage', - }, - { - 'id': 'permanent', - 'icon': LucideIcons.users, - 'title': 'Permanent', - 'description': 'Long-Term Staffing Placement', - }, - ]; - - Map _getTypeColors(String id) { - switch (id) { - case 'rapid': - return { - 'bg': const Color(0xFFFEF2F2), // red-50 - 'border': const Color(0xFFFECACA), // red-200 - 'iconBg': const Color(0xFFFEE2E2), // red-100 - 'icon': const Color(0xFFDC2626), // red-600 - 'text': const Color(0xFF7F1D1D), // red-900 - 'desc': const Color(0xFFB91C1C), // red-700 - }; - case 'one-time': - return { - 'bg': const Color(0xFFEFF6FF), // blue-50 - 'border': const Color(0xFFBFDBFE), // blue-200 - 'iconBg': const Color(0xFFDBEAFE), // blue-100 - 'icon': const Color(0xFF2563EB), // blue-600 - 'text': const Color(0xFF1E3A8A), // blue-900 - 'desc': const Color(0xFF1D4ED8), // blue-700 - }; - case 'recurring': - return { - 'bg': const Color(0xFFFAF5FF), // purple-50 - 'border': const Color(0xFFE9D5FF), // purple-200 - 'iconBg': const Color(0xFFF3E8FF), // purple-100 - 'icon': const Color(0xFF9333EA), // purple-600 - 'text': const Color(0xFF581C87), // purple-900 - 'desc': const Color(0xFF7E22CE), // purple-700 - }; - case 'permanent': - return { - 'bg': const Color(0xFFF0FDF4), // green-50 - 'border': const Color(0xFFBBF7D0), // green-200 - 'iconBg': const Color(0xFFDCFCE7), // green-100 - 'icon': const Color(0xFF16A34A), // green-600 - 'text': const Color(0xFF14532D), // green-900 - 'desc': const Color(0xFF15803D), // green-700 - }; - default: - return { - 'bg': Colors.white, - 'border': AppColors.krowBorder, - 'iconBg': AppColors.krowBackground, - 'icon': AppColors.krowMuted, - 'text': AppColors.krowCharcoal, - 'desc': AppColors.krowMuted, - }; - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: AppColors.krowBorder, height: 1.0), - ), - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: AppColors.krowMuted), - onPressed: () => context.go('/client-home'), - ), - title: const Text( - 'Create Order', - style: TextStyle( - color: AppColors.krowCharcoal, - fontWeight: FontWeight.w600, - fontSize: 18, - ), - ), - ), - body: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsets.only(bottom: 24), - child: Text( - 'ORDER TYPE', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowMuted, - letterSpacing: 0.5, // Matches tracking-wide approx - ), - ), - ), - Expanded( - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - mainAxisSpacing: 16, - crossAxisSpacing: 16, - childAspectRatio: 1, // Adjust for layout - ), - itemCount: _orderTypes.length, - itemBuilder: (context, index) { - final type = _orderTypes[index]; - final colors = _getTypeColors(type['id']); - - return _OrderTypeCard( - icon: type['icon'], - title: type['title'], - description: type['description'], - colors: colors, - onTap: () { - String routePath = ''; - switch (type['id']) { - case 'rapid': - routePath = '/create-order/rapid'; - break; - case 'one-time': - routePath = '/create-order/one-time'; - break; - case 'recurring': - routePath = '/create-order/recurring'; - break; - case 'permanent': - routePath = '/create-order/permanent'; - break; - } - context.push(routePath); - }, - ); - }, - ), - ), - ], - ), - ), - ), - ); - } -} - -class _OrderTypeCard extends StatelessWidget { - final IconData icon; - final String title; - final String description; - final Map colors; - final VoidCallback onTap; - - const _OrderTypeCard({ - required this.icon, - required this.title, - required this.description, - required this.colors, - required this.onTap, - }); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: colors['bg'], - borderRadius: BorderRadius.circular(8), // rounded-lg - border: Border.all(color: colors['border'], width: 2), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - width: 48, - height: 48, - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: colors['iconBg'], - borderRadius: BorderRadius.circular(8), // rounded-lg - ), - child: Icon(icon, color: colors['icon'], size: 24), - ), - Text( - title, - style: TextStyle( - fontSize: 14, // text-sm - fontWeight: FontWeight.w600, // font-semibold - color: colors['text'], - ), - ), - const SizedBox(height: 4), - Text( - description, - style: TextStyle( - fontSize: 12, // text-xs - color: colors['desc'], - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/coverage_report_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/coverage_report_screen.dart deleted file mode 100644 index c5858edb..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/coverage_report_screen.dart +++ /dev/null @@ -1,449 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; - -class CoverageReportScreen extends StatelessWidget { - const CoverageReportScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF0A39DF), Color(0xFF0830B8)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Coverage Report', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Staffing levels & gaps', - style: TextStyle( - fontSize: 12, - color: Colors.white70, - ), - ), - ], - ), - ], - ), - GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Exporting Coverage Report (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - LucideIcons.download, - size: 14, - color: Color(0xFF0A39DF), - ), - SizedBox(width: 6), - Text( - 'Export', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ], - ), - ), - - // Content - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Summary Cards - Row( - children: [ - const Expanded( - child: _CoverageStatCard( - label: 'Avg Coverage', - value: '96%', - icon: LucideIcons.trendingUp, - color: Color(0xFF7C3AED), // violet-600 - ), - ), - const SizedBox(width: 8), - const Expanded( - child: _CoverageStatCard( - label: 'Full', - value: '5', - icon: LucideIcons.checkCircle2, - color: Color(0xFF059669), // emerald-600 - ), - ), - const SizedBox(width: 8), - const Expanded( - child: _CoverageStatCard( - label: 'Needs Help', - value: '2', - icon: LucideIcons.alertCircle, - color: Color(0xFFDC2626), // red-600 - ), - ), - ], - ), - const SizedBox(height: 24), - - const Text( - 'NEXT 7 DAYS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF64748B), - letterSpacing: 1.2, - ), - ), - const SizedBox(height: 12), - - // Daily Coverage List - const _DailyCoverageItem( - date: 'Sat, Dec 20', - confirmed: 12, - needed: 12, - coverage: 100, - ), - const _DailyCoverageItem( - date: 'Sun, Dec 21', - confirmed: 8, - needed: 10, - coverage: 80, - ), - const _DailyCoverageItem( - date: 'Mon, Dec 22', - confirmed: 15, - needed: 15, - coverage: 100, - ), - const _DailyCoverageItem( - date: 'Tue, Dec 23', - confirmed: 5, - needed: 8, - coverage: 62, - ), - const _DailyCoverageItem( - date: 'Wed, Dec 24', - confirmed: 12, - needed: 12, - coverage: 100, - ), - - const SizedBox(height: 24), - - // Insights Card - Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFF5F3FF), Color(0xFFEDE9FE)], - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFF7C3AED).withOpacity(0.1), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 Coverage Insights', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 12), - _insightRow( - 'Your average coverage rate is ', - '96%', - ' - above industry standard', - ), - _insightRow( - '', - '2 days', - ' need immediate attention to reach full coverage', - ), - _insightRow( - 'Weekend coverage is typically ', - '98%', - ' vs weekday 94%', - ), - ], - ), - ), - const SizedBox(height: 100), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _insightRow(String prefix, String bold, String suffix) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('• ', style: TextStyle(color: Color(0xFF334155))), - Expanded( - child: RichText( - text: TextSpan( - style: const TextStyle( - color: Color(0xFF334155), - fontSize: 13, - height: 1.4, - ), - children: [ - TextSpan(text: prefix), - TextSpan( - text: bold, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: suffix), - ], - ), - ), - ), - ], - ), - ); - } -} - -class _CoverageStatCard extends StatelessWidget { - final String label; - final String value; - final IconData icon; - final Color color; - - const _CoverageStatCard({ - required this.label, - required this.value, - required this.icon, - required this.color, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 12, color: color), - const SizedBox(width: 4), - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - const SizedBox(height: 8), - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - ], - ), - ); - } -} - -class _DailyCoverageItem extends StatelessWidget { - final String date; - final int confirmed; - final int needed; - final int coverage; - - const _DailyCoverageItem({ - required this.date, - required this.confirmed, - required this.needed, - required this.coverage, - }); - - @override - Widget build(BuildContext context) { - Color getStatusColor() { - if (coverage == 100) return const Color(0xFF059669); - if (coverage >= 80) return const Color(0xFF2563EB); - return const Color(0xFFDC2626); - } - - Color getStatusBg() { - if (coverage == 100) return const Color(0xFFD1FAE5); - if (coverage >= 80) return const Color(0xFFDBEAFE); - return const Color(0xFFFEE2E2); - } - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - date, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - Text( - '$confirmed/$needed workers confirmed', - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - ), - ], - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: getStatusBg(), - borderRadius: BorderRadius.circular(6), - ), - child: Text( - '$coverage%', - style: TextStyle( - color: getStatusColor(), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 12), - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: LinearProgressIndicator( - value: coverage / 100, - backgroundColor: const Color(0xFFF1F5F9), - valueColor: AlwaysStoppedAnimation(getStatusColor()), - minHeight: 6, - ), - ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - needed - confirmed > 0 - ? '${needed - confirmed} spots remaining' - : 'Fully staffed', - style: const TextStyle(fontSize: 10, color: Color(0xFF94A3B8)), - ), - ], - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/daily_ops_report_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/daily_ops_report_screen.dart deleted file mode 100644 index 69d785d6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/daily_ops_report_screen.dart +++ /dev/null @@ -1,517 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; - -class DailyOpsReportScreen extends StatefulWidget { - const DailyOpsReportScreen({super.key}); - - @override - State createState() => _DailyOpsReportScreenState(); -} - -class _DailyOpsReportScreenState extends State { - DateTime selectedDate = DateTime.now(); - - Future _selectDate(BuildContext context) async { - final DateTime? picked = await showDatePicker( - context: context, - initialDate: selectedDate, - firstDate: DateTime(2020), - lastDate: DateTime(2030), - ); - if (picked != null && picked != selectedDate) { - setState(() { - selectedDate = picked; - }); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header with Gradient - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [ - Color(0xFF0A39DF), // Krow Blue - Color(0xFF0830B8), // Darker Blue - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Daily Ops Report', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Real-time shift tracking', - style: TextStyle( - fontSize: 12, - color: Colors.white.withOpacity(0.8), - ), - ), - ], - ), - ], - ), - GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Exporting Daily Operations Report (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - LucideIcons.download, - size: 14, - color: Color(0xFF0A39DF), - ), - SizedBox(width: 6), - Text( - 'Export', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ], - ), - ], - ), - ), - - // Content - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Date Selector - GestureDetector( - onTap: () => _selectDate(context), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 12, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 18, - color: Color(0xFF64748B), - ), - const SizedBox(width: 12), - Text( - DateFormat('yyyy-MM-dd').format(selectedDate), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF1E293B), - ), - ), - const Spacer(), - const Icon( - LucideIcons.chevronDown, - size: 16, - color: Color(0xFF64748B), - ), - ], - ), - ), - ), - const SizedBox(height: 20), - - // Summary Stats - GridView.count( - padding: EdgeInsets.zero, - crossAxisCount: 2, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.4, - children: const [ - _OpsStatCard( - icon: LucideIcons.calendar, - label: 'Scheduled', - value: '12', - subValue: 'shifts', - iconColor: Color(0xFF2563EB), - badgeColor: Color(0xFFDBEAFE), - badgeTextColor: Color(0xFF1D4ED8), - ), - _OpsStatCard( - icon: LucideIcons.users, - label: 'Workers', - value: '45/48', - subValue: 'confirmed', - iconColor: Color(0xFF7C3AED), - badgeColor: Color(0xFFF3E8FF), - badgeTextColor: Color(0xFF6D28D9), - ), - _OpsStatCard( - icon: LucideIcons.clock, - label: 'In Progress', - value: '4', - subValue: 'active now', - iconColor: Color(0xFFD97706), - badgeColor: Color(0xFFFEF3C7), - badgeTextColor: Color(0xFFB45309), - ), - _OpsStatCard( - icon: LucideIcons.checkCircle2, - label: 'Completed', - value: '8', - subValue: 'done today', - iconColor: Color(0xFF059669), - badgeColor: Color(0xFFD1FAE5), - badgeTextColor: Color(0xFF047857), - ), - ], - ), - - const SizedBox(height: 24), - - const Text( - 'ALL SHIFTS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF64748B), - letterSpacing: 1.2, - ), - ), - const SizedBox(height: 12), - - // Shift List - const _ShiftListItem( - title: 'Night Shift - Logistics', - location: 'Hub 4, North Zone', - startTime: '22:00', - endTime: '06:00', - workersNeeded: '8', - filled: '8', - hourlyRate: '\$18', - status: 'IN_PROGRESS', - statusColor: Color(0xFFD97706), - statusBg: Color(0xFFFEF3C7), - ), - const _ShiftListItem( - title: 'Morning Delivery Support', - location: 'East Side Hub', - startTime: '08:00', - endTime: '16:00', - workersNeeded: '12', - filled: '12', - hourlyRate: '\$16', - status: 'COMPLETED', - statusColor: Color(0xFF059669), - statusBg: Color(0xFFD1FAE5), - ), - const _ShiftListItem( - title: 'Warehouse Sorting', - location: 'Hub 2, South', - startTime: '09:00', - endTime: '17:00', - workersNeeded: '15', - filled: '15', - hourlyRate: '\$17', - status: 'COMPLETED', - statusColor: Color(0xFF059669), - statusBg: Color(0xFFD1FAE5), - ), - const SizedBox(height: 100), - ], - ), - ), - ), - ], - ), - ), - ); - } -} - -class _OpsStatCard extends StatelessWidget { - final IconData icon; - final String label; - final String value; - final String subValue; - final Color iconColor; - final Color badgeColor; - final Color badgeTextColor; - - const _OpsStatCard({ - required this.icon, - required this.label, - required this.value, - required this.subValue, - required this.iconColor, - required this.badgeColor, - required this.badgeTextColor, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Icon(icon, size: 14, color: iconColor), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: badgeColor, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - subValue, - style: TextStyle( - fontSize: 8, - fontWeight: FontWeight.bold, - color: badgeTextColor, - ), - ), - ), - ], - ), - ], - ), - ); - } -} - -class _ShiftListItem extends StatelessWidget { - final String title; - final String location; - final String startTime; - final String endTime; - final String workersNeeded; - final String filled; - final String hourlyRate; - final String status; - final Color statusColor; - final Color statusBg; - - const _ShiftListItem({ - required this.title, - required this.location, - required this.startTime, - required this.endTime, - required this.workersNeeded, - required this.filled, - required this.hourlyRate, - required this.status, - required this.statusColor, - required this.statusBg, - }); - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - const SizedBox(height: 4), - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: Color(0xFF94A3B8), - ), - const SizedBox(width: 4), - Text( - location, - style: const TextStyle( - fontSize: 11, - color: Color(0xFF64748B), - ), - ), - ], - ), - ], - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: statusBg, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - status, - style: TextStyle( - color: statusColor, - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _infoItem('Time', startTime + ' - ' + endTime), - _infoItem('Workers', workersNeeded + '/' + filled), - _infoItem('Rate', '$hourlyRate/hr'), - ], - ), - ], - ), - ); - } - - Widget _infoItem(String label, String value) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF94A3B8)), - ), - const SizedBox(height: 2), - Text( - value, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF1E293B), - ), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/forecast_report_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/forecast_report_screen.dart deleted file mode 100644 index d8050356..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/forecast_report_screen.dart +++ /dev/null @@ -1,587 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'package:fl_chart/fl_chart.dart'; - -class ForecastReportScreen extends StatelessWidget { - const ForecastReportScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF0A39DF), Color(0xFF121826)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Forecast Report', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Next 4 weeks projection', - style: TextStyle( - fontSize: 12, - color: Colors.white70, - ), - ), - ], - ), - ], - ), - GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Exporting Forecast Report (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - LucideIcons.download, - size: 14, - color: Color(0xFF0A39DF), - ), - SizedBox(width: 6), - Text( - 'Export', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ], - ), - ), - - // Content - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Summary Cards Grid - GridView.count( - padding: EdgeInsets.zero, - crossAxisCount: 2, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.4, - children: const [ - _ForecastStatCard( - label: '4-Week Forecast', - value: '\$45,200', - badge: 'Total projected', - icon: LucideIcons.dollarSign, - color: Color(0xFFD97706), // amber-600 - bgColor: Color(0xFFFEF3C7), // amber-100 - ), - _ForecastStatCard( - label: 'Avg Weekly', - value: '\$11,300', - badge: 'Per week', - icon: LucideIcons.trendingUp, - color: Color(0xFF2563EB), // blue-600 - bgColor: Color(0xFFDBEAFE), // blue-100 - ), - _ForecastStatCard( - label: 'Total Shifts', - value: '124', - badge: 'Scheduled', - icon: LucideIcons.calendar, - color: Color(0xFF7C3AED), // violet-600 - bgColor: Color(0xFFF3E8FF), // violet-100 - ), - _ForecastStatCard( - label: 'Total Hours', - value: '992', - badge: 'Worker hours', - icon: LucideIcons.users, - color: Color(0xFF059669), // emerald-600 - bgColor: Color(0xFFD1FAE5), // emerald-100 - ), - ], - ), - const SizedBox(height: 24), - - // Chart Card - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 10, - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Spending Forecast', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 24), - SizedBox( - height: 180, - child: LineChart( - LineChartData( - gridData: FlGridData( - show: true, - drawVerticalLine: false, - horizontalInterval: 5000, - getDrawingHorizontalLine: (value) { - return FlLine( - color: const Color(0xFFE2E8F0), - strokeWidth: 1, - ); - }, - ), - titlesData: FlTitlesData( - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) { - const titles = ['W1', 'W2', 'W3', 'W4']; - if (value.toInt() < titles.length) { - return Padding( - padding: const EdgeInsets.only( - top: 8, - ), - child: Text( - titles[value.toInt()], - style: const TextStyle( - color: Color(0xFF94A3B8), - fontSize: 10, - ), - ), - ); - } - return const SizedBox.shrink(); - }, - ), - ), - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 40, - getTitlesWidget: (value, meta) { - if (value % 5000 == 0 && value > 0) { - return Text( - '\$${(value / 1000).toInt()}k', - style: const TextStyle( - color: Color(0xFF94A3B8), - fontSize: 10, - ), - ); - } - return const SizedBox.shrink(); - }, - ), - ), - topTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - rightTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - ), - borderData: FlBorderData(show: false), - lineBarsData: [ - LineChartBarData( - spots: const [ - FlSpot(0, 10240), - FlSpot(1, 12480), - FlSpot(2, 11320), - FlSpot(3, 11160), - ], - isCurved: true, - color: const Color(0xFFF59E0B), - barWidth: 3, - dotData: const FlDotData(show: true), - belowBarData: BarAreaData( - show: true, - color: const Color( - 0xFFF59E0B, - ).withOpacity(0.1), - ), - ), - ], - minY: 5000, - maxY: 15000, - ), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - - const Text( - 'WEEKLY BREAKDOWN', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF64748B), - letterSpacing: 1.2, - ), - ), - const SizedBox(height: 12), - - // Weekly Breakdown List - const _WeeklyBreakdownItem( - week: 'Week 1', - spend: '\$10,240', - shifts: '32', - hours: '256', - ), - const _WeeklyBreakdownItem( - week: 'Week 2', - spend: '\$12,480', - shifts: '38', - hours: '304', - ), - const _WeeklyBreakdownItem( - week: 'Week 3', - spend: '\$11,320', - shifts: '30', - hours: '240', - ), - const _WeeklyBreakdownItem( - week: 'Week 4', - spend: '\$11,160', - shifts: '24', - hours: '192', - ), - const SizedBox(height: 24), - - // Insights Card - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFFEF3C7), Color(0xFFFFF7ED)], - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFF59E0B).withOpacity(0.1), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 Forecast Insights', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 12), - _insightRow( - 'Week 3 has ', - 'highest projected spend', - ' - plan ahead', - ), - _insightRow( - 'Average cost per shift is ', - '\$350', - '', - ), - _insightRow( - 'Consider bulk scheduling to save ', - '12%', - ' on booking fees', - ), - ], - ), - ), - const SizedBox(height: 100), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _insightRow(String prefix, String bold, String suffix) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('• ', style: TextStyle(color: Color(0xFF334155))), - Expanded( - child: RichText( - text: TextSpan( - style: const TextStyle( - color: Color(0xFF334155), - fontSize: 13, - height: 1.4, - ), - children: [ - TextSpan(text: prefix), - TextSpan( - text: bold, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: suffix), - ], - ), - ), - ), - ], - ), - ); - } -} - -class _ForecastStatCard extends StatelessWidget { - final String label; - final String value; - final String badge; - final IconData icon; - final Color color; - final Color bgColor; - - const _ForecastStatCard({ - required this.label, - required this.value, - required this.badge, - required this.icon, - required this.color, - required this.bgColor, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Icon(icon, size: 14, color: color), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: bgColor, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - badge, - style: TextStyle( - fontSize: 8, - fontWeight: FontWeight.bold, - color: color, - ), - ), - ), - ], - ), - ], - ), - ); - } -} - -class _WeeklyBreakdownItem extends StatelessWidget { - final String week; - final String spend; - final String shifts; - final String hours; - - const _WeeklyBreakdownItem({ - required this.week, - required this.spend, - required this.shifts, - required this.hours, - }); - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - week, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: const Color(0xFFFEF3C7), // amber-100 - borderRadius: BorderRadius.circular(6), - ), - child: Text( - spend, - style: const TextStyle( - color: Color(0xFFB45309), // amber-700 - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _infoItem('Shifts', shifts), - _infoItem('Hours', hours), - _infoItem( - 'Avg/Shift', - '\$${(double.parse(spend.replaceAll('\$', '').replaceAll(',', '')) / double.parse(shifts)).toStringAsFixed(0)}', - ), - ], - ), - ], - ), - ); - } - - Widget _infoItem(String label, String value) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF94A3B8)), - ), - const SizedBox(height: 2), - Text( - value, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF1E293B), - ), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/no_show_report_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/no_show_report_screen.dart deleted file mode 100644 index 96d41ad3..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/no_show_report_screen.dart +++ /dev/null @@ -1,441 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; - -class NoShowReportScreen extends StatelessWidget { - const NoShowReportScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF121826), Color(0xFF2D3748)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'No-Show Report', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Reliability tracking', - style: TextStyle( - fontSize: 12, - color: Colors.white70, - ), - ), - ], - ), - ], - ), - GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Exporting No-Show Report (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - LucideIcons.download, - size: 14, - color: Color(0xFF121826), - ), - SizedBox(width: 6), - Text( - 'Export', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ], - ), - ), - - // Content - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Summary Cards - Row( - children: [ - const Expanded( - child: _NoShowStatCard( - label: 'No-Shows', - value: '4', - icon: LucideIcons.xCircle, - color: Color(0xFFDC2626), // red-600 - ), - ), - const SizedBox(width: 8), - const Expanded( - child: _NoShowStatCard( - label: 'Rate', - value: '1.2%', - icon: LucideIcons.trendingDown, - color: Color(0xFF059669), // emerald-600 - ), - ), - const SizedBox(width: 8), - const Expanded( - child: _NoShowStatCard( - label: 'Workers', - value: '3', - icon: LucideIcons.user, - color: Color(0xFF7C3AED), // violet-600 - ), - ), - ], - ), - const SizedBox(height: 24), - - const Text( - 'WORKERS WITH NO-SHOWS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF64748B), - letterSpacing: 1.2, - ), - ), - const SizedBox(height: 12), - - // Workers List - const _WorkerNoShowItem( - name: 'James Wilson', - count: 2, - latestIncident: 'Dec 12, 2025', - risk: 'High Risk', - ), - const _WorkerNoShowItem( - name: 'Sarah Parker', - count: 1, - latestIncident: 'Dec 05, 2025', - risk: 'Medium Risk', - ), - const _WorkerNoShowItem( - name: 'Mike Ross', - count: 1, - latestIncident: 'Nov 28, 2025', - risk: 'Low Risk', - ), - - const SizedBox(height: 24), - - // Insights Card - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFFEF2F2), Color(0xFFFFF1F2)], - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFDC2626).withOpacity(0.1), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 Reliability Insights', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 12), - _insightRow( - 'Your no-show rate of ', - '1.2%', - ' is below industry average', - ), - _insightRow( - '', - '1 worker', - ' has multiple incidents this month', - ), - _insightRow( - 'Consider implementing ', - 'confirmation reminders', - ' 24hrs before shifts', - ), - ], - ), - ), - const SizedBox(height: 100), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _insightRow(String prefix, String bold, String suffix) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('• ', style: TextStyle(color: Color(0xFF334155))), - Expanded( - child: RichText( - text: TextSpan( - style: const TextStyle( - color: Color(0xFF334155), - fontSize: 13, - height: 1.4, - ), - children: [ - TextSpan(text: prefix), - TextSpan( - text: bold, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: suffix), - ], - ), - ), - ), - ], - ), - ); - } -} - -class _NoShowStatCard extends StatelessWidget { - final String label; - final String value; - final IconData icon; - final Color color; - - const _NoShowStatCard({ - required this.label, - required this.value, - required this.icon, - required this.color, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 12, color: color), - const SizedBox(width: 4), - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - const SizedBox(height: 8), - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - ], - ), - ); - } -} - -class _WorkerNoShowItem extends StatelessWidget { - final String name; - final int count; - final String latestIncident; - final String risk; - - const _WorkerNoShowItem({ - required this.name, - required this.count, - required this.latestIncident, - required this.risk, - }); - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Color(0xFFFEE2E2), // red-100 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.user, - size: 20, - color: Color(0xFFDC2626), // red-600 - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - name, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - Text( - '$count no-show${count > 1 ? 's' : ''}', - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - ), - ], - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: risk == 'High Risk' - ? const Color(0xFFFEE2E2) - : const Color(0xFFF1F5F9), - borderRadius: BorderRadius.circular(6), - ), - child: Text( - risk, - style: TextStyle( - color: risk == 'High Risk' - ? const Color(0xFFDC2626) - : const Color(0xFF64748B), - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 12), - const Divider(height: 1, color: Color(0xFFF1F5F9)), - const SizedBox(height: 12), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Latest incident', - style: TextStyle(fontSize: 11, color: Color(0xFF94A3B8)), - ), - Text( - latestIncident, - style: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.bold, - color: Color(0xFF475569), - ), - ), - ], - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/performance_report_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/performance_report_screen.dart deleted file mode 100644 index a70e8a81..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/performance_report_screen.dart +++ /dev/null @@ -1,523 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; - -class PerformanceReportScreen extends StatelessWidget { - const PerformanceReportScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF0A39DF), Color(0xFF0830B8)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Performance Report', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Key metrics & benchmarks', - style: TextStyle( - fontSize: 12, - color: Colors.white70, - ), - ), - ], - ), - ], - ), - GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Exporting Performance Report (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - LucideIcons.download, - size: 14, - color: Color(0xFF0A39DF), - ), - SizedBox(width: 6), - Text( - 'Export', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ], - ), - ), - - // Content - Transform.translate( - offset: const Offset(0, 16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Overall Score Card - Container( - width: double.infinity, - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: const Color(0xFF0A39DF).withOpacity(0.05), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - gradient: LinearGradient( - colors: [ - const Color(0xFF0A39DF).withOpacity(0.05), - const Color(0xFF121826).withOpacity(0.05), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - children: [ - const Icon( - LucideIcons.barChart3, - size: 32, - color: Color(0xFF0A39DF), - ), - const SizedBox(height: 12), - const Text( - 'Overall Performance Score', - style: TextStyle( - fontSize: 13, - color: Color(0xFF64748B), - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 4), - const Text( - '94/100', - style: TextStyle( - fontSize: 40, - fontWeight: FontWeight.bold, - color: Color(0xFF0A39DF), - letterSpacing: -1, - ), - ), - const SizedBox(height: 12), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 4, - ), - decoration: BoxDecoration( - color: const Color(0xFF0A39DF).withOpacity(0.1), - borderRadius: BorderRadius.circular(20), - ), - child: const Text( - 'Excellent', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - - const Text( - 'KEY PERFORMANCE INDICATORS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF64748B), - letterSpacing: 1.2, - ), - ), - const SizedBox(height: 12), - - // KPIs List - const _PerformanceKPI( - label: 'Fill Rate', - value: '96%', - target: '95%', - icon: LucideIcons.target, - color: Color(0xFF2563EB), - bgColor: Color(0xFFDBEAFE), - ), - const _PerformanceKPI( - label: 'Completion Rate', - value: '98%', - target: '98%', - icon: LucideIcons.checkCircle2, - color: Color(0xFF059669), - bgColor: Color(0xFFD1FAE5), - ), - const _PerformanceKPI( - label: 'On-Time Rate', - value: '95%', - target: '97%', - icon: LucideIcons.clock, - color: Color(0xFF7C3AED), - bgColor: Color(0xFFF3E8FF), - ), - const _PerformanceKPI( - label: 'Avg Fill Time', - value: '2.4 hrs', - target: '3 hrs', - icon: LucideIcons.trendingUp, - color: Color(0xFFD97706), - bgColor: Color(0xFFFEF3C7), - ), - - const SizedBox(height: 24), - - const Text( - 'ADDITIONAL METRICS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF64748B), - letterSpacing: 1.2, - ), - ), - const SizedBox(height: 12), - - // Small Metrics Grid - GridView.count( - padding: EdgeInsets.zero, - crossAxisCount: 2, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.8, - children: const [ - _SmallMetric(label: 'Total Shifts', value: '156'), - _SmallMetric(label: 'No-Show Rate', value: '1.2%'), - _SmallMetric(label: 'Worker Pool', value: '450'), - _SmallMetric(label: 'Avg Rating', value: '4.8 ⭐'), - ], - ), - - const SizedBox(height: 24), - - // Insights Card - Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - const Color(0xFF0A39DF).withOpacity(0.05), - const Color(0xFF121826).withOpacity(0.05), - ], - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFF0A39DF).withOpacity(0.1), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 Performance Insights', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 12), - _insightRow( - 'You\'re ', - 'outperforming 87%', - ' of similar businesses', - ), - _insightRow( - 'Fill rate is ', - 'above target', - ' - maintain practices', - ), - _insightRow( - '', - 'Worker bonuses', - ' could improve retention further', - ), - ], - ), - ), - const SizedBox(height: 100), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _insightRow(String prefix, String bold, String suffix) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('• ', style: TextStyle(color: Color(0xFF334155))), - Expanded( - child: RichText( - text: TextSpan( - style: const TextStyle( - color: Color(0xFF334155), - fontSize: 13, - height: 1.4, - ), - children: [ - TextSpan(text: prefix), - TextSpan( - text: bold, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: suffix), - ], - ), - ), - ), - ], - ), - ); - } -} - -class _PerformanceKPI extends StatelessWidget { - final String label; - final String value; - final String target; - final IconData icon; - final Color color; - final Color bgColor; - - const _PerformanceKPI({ - required this.label, - required this.value, - required this.target, - required this.icon, - required this.color, - required this.bgColor, - }); - - @override - Widget build(BuildContext context) { - bool metTarget = true; // Simplified for demo - if (label == 'On-Time Rate') metTarget = false; - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: bgColor, - borderRadius: BorderRadius.circular(12), - ), - child: Icon(icon, size: 20, color: color), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - Text( - 'Target: $target', - style: const TextStyle( - fontSize: 11, - color: Color(0xFF64748B), - ), - ), - ], - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: metTarget - ? const Color(0xFFD1FAE5) - : const Color(0xFFFEF3C7), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - metTarget ? '✓ Met' : '↗ Close', - style: TextStyle( - color: metTarget - ? const Color(0xFF059669) - : const Color(0xFFD97706), - fontSize: 8, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ], - ), - const SizedBox(height: 12), - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: LinearProgressIndicator( - value: metTarget ? 0.98 : 0.95, - backgroundColor: const Color(0xFFF1F5F9), - valueColor: AlwaysStoppedAnimation(color), - minHeight: 6, - ), - ), - ], - ), - ); - } -} - -class _SmallMetric extends StatelessWidget { - final String label; - final String value; - - const _SmallMetric({required this.label, required this.value}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - label, - style: const TextStyle(fontSize: 11, color: Color(0xFF64748B)), - ), - const SizedBox(height: 4), - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/spend_report_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/spend_report_screen.dart deleted file mode 100644 index 1f9f9acc..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/reports/spend_report_screen.dart +++ /dev/null @@ -1,563 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'package:fl_chart/fl_chart.dart'; - -class SpendReportScreen extends StatelessWidget { - const SpendReportScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 - body: SingleChildScrollView( - child: Column( - children: [ - // Header - Container( - padding: const EdgeInsets.only( - top: 60, - left: 20, - right: 20, - bottom: 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF0A39DF), Color(0xFF0830B8)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Spend Report', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - Text( - 'Cost analysis & breakdown', - style: TextStyle( - fontSize: 12, - color: Colors.white70, - ), - ), - ], - ), - ], - ), - GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Exporting Spend Report (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - }, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - children: [ - Icon( - LucideIcons.download, - size: 14, - color: Color(0xFF0A39DF), - ), - SizedBox(width: 6), - Text( - 'Export', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - ), - ], - ), - ), - - // Content - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - // Summary Cards - Row( - children: [ - const Expanded( - child: _SpendSummaryCard( - label: 'Total Spend', - value: '\$17,200', - badge: 'This week', - icon: LucideIcons.dollarSign, - color: Color(0xFF059669), // emerald-600 - badgeBg: Color(0xFFD1FAE5), // emerald-100 - ), - ), - const SizedBox(width: 12), - const Expanded( - child: _SpendSummaryCard( - label: 'Avg Daily', - value: '\$2,457', - badge: 'Per day', - icon: LucideIcons.trendingUp, - color: Color(0xFF2563EB), // blue-600 - badgeBg: Color(0xFFDBEAFE), // blue-100 - ), - ), - ], - ), - const SizedBox(height: 20), - - // Chart Card - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 10, - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Daily Spend Trend', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 24), - SizedBox( - height: 180, - child: BarChart( - BarChartData( - alignment: BarChartAlignment.spaceAround, - maxY: 5000, - barTouchData: BarTouchData(enabled: false), - titlesData: FlTitlesData( - show: true, - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - getTitlesWidget: (value, meta) { - const titles = [ - 'Mon', - 'Tue', - 'Wed', - 'Thu', - 'Fri', - 'Sat', - 'Sun', - ]; - if (value.toInt() < titles.length) { - return Padding( - padding: const EdgeInsets.only( - top: 8.0, - ), - child: Text( - titles[value.toInt()], - style: const TextStyle( - color: Color(0xFF64748B), - fontSize: 10, - ), - ), - ); - } - return const SizedBox.shrink(); - }, - ), - ), - leftTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 40, - getTitlesWidget: (value, meta) { - if (value % 1000 == 0) { - return Text( - '\$${(value / 1000).toInt()}k', - style: const TextStyle( - color: Color(0xFF64748B), - fontSize: 10, - ), - ); - } - return const SizedBox.shrink(); - }, - ), - ), - topTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - rightTitles: const AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - ), - gridData: FlGridData( - show: true, - drawVerticalLine: false, - horizontalInterval: 1000, - getDrawingHorizontalLine: (value) { - return FlLine( - color: const Color(0xFFE2E8F0), - strokeWidth: 1, - ); - }, - ), - borderData: FlBorderData(show: false), - barGroups: [ - _makeGroupData(0, 1200), - _makeGroupData(1, 1800), - _makeGroupData(2, 2400), - _makeGroupData(3, 1600), - _makeGroupData(4, 3200), - _makeGroupData(5, 4100), - _makeGroupData(6, 2800), - ], - ), - ), - ), - ], - ), - ), - const SizedBox(height: 20), - - // Industry Breakdown - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 10, - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Spend by Industry', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 20), - _IndustryRow( - name: 'Hospitality', - value: '\$8,500', - percent: 49.4, - ), - const SizedBox(height: 16), - _IndustryRow( - name: 'Events', - value: '\$5,200', - percent: 30.2, - ), - const SizedBox(height: 16), - _IndustryRow( - name: 'Retail', - value: '\$3,500', - percent: 20.4, - ), - ], - ), - ), - const SizedBox(height: 20), - - // Insights Card - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFDCFCE7), Color(0xFFF0FDF4)], - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFF059669).withOpacity(0.1), - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - '💡 Cost Insights', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - color: Color(0xFF065F46), - ), - ), - const SizedBox(height: 12), - _insightRow( - 'Spending is ', - '8.2% higher', - ' than last week', - ), - _insightRow( - 'Weekend shifts account for ', - '40%', - ' of total spend', - ), - _insightRow( - 'Book 48hrs ahead to save ', - '15%', - ' on average', - ), - ], - ), - ), - const SizedBox(height: 100), - ], - ), - ), - ), - ], - ), - ), - ); - } - - BarChartGroupData _makeGroupData(int x, double y) { - return BarChartGroupData( - x: x, - barRods: [ - BarChartRodData( - toY: y, - color: const Color(0xFF10B981), - width: 16, - borderRadius: const BorderRadius.vertical(top: Radius.circular(4)), - ), - ], - ); - } - - Widget _insightRow(String prefix, String bold, String suffix) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('• ', style: TextStyle(color: Color(0xFF065F46))), - Expanded( - child: RichText( - text: TextSpan( - style: const TextStyle( - color: Color(0xFF065F46), - fontSize: 13, - height: 1.4, - ), - children: [ - TextSpan(text: prefix), - TextSpan( - text: bold, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan(text: suffix), - ], - ), - ), - ), - ], - ), - ); - } -} - -class _SpendSummaryCard extends StatelessWidget { - final String label; - final String value; - final String badge; - final IconData icon; - final Color color; - final Color badgeBg; - - const _SpendSummaryCard({ - required this.label, - required this.value, - required this.badge, - required this.icon, - required this.color, - required this.badgeBg, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.06), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 14, color: color), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - const SizedBox(height: 12), - Text( - value, - style: const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - decoration: BoxDecoration( - color: badgeBg, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - badge, - style: TextStyle( - fontSize: 8, - fontWeight: FontWeight.bold, - color: color, - ), - ), - ), - ], - ), - ); - } -} - -class _IndustryRow extends StatelessWidget { - final String name; - final String value; - final double percent; - - const _IndustryRow({ - required this.name, - required this.value, - required this.percent, - }); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - name, - style: const TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), - ), - ), - Text( - value, - style: const TextStyle( - fontSize: 13, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - ], - ), - const SizedBox(height: 8), - Stack( - children: [ - Container( - height: 8, - width: double.infinity, - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), - borderRadius: BorderRadius.circular(4), - ), - ), - FractionallySizedBox( - widthFactor: percent / 100, - child: Container( - height: 8, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFF10B981), Color(0xFF059669)], - ), - borderRadius: BorderRadius.circular(4), - ), - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - '$percent% of total', - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/verify_worker_attire_screen.dart b/apps/mobile/prototypes/client_mobile_application/lib/screens/client/verify_worker_attire_screen.dart deleted file mode 100644 index 0542cc1b..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/screens/client/verify_worker_attire_screen.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; - -class VerifyWorkerAttireScreen extends StatefulWidget { - const VerifyWorkerAttireScreen({super.key}); - - @override - State createState() => _VerifyWorkerAttireScreenState(); -} - -class _VerifyWorkerAttireScreenState extends State { - // Mock Data - final List> _staff = [ - { - 'id': '93673c8f-91aa-405d-8647-f1aac29cc191', - 'email': 'worker1@example.com', - 'itemsAttire': [ - {'id': 'non_slip_shoes', 'label': 'Non Slip Shoes', 'verified': false}, - {'id': 'black_pants', 'label': 'Black Pants', 'verified': false}, - ] - }, - { - 'id': '93673c8f-91aa-405d-8647-f1aac29cc192', - 'email': 'worker2@example.com', - 'itemsAttire': [ - {'id': 'white_polo', 'label': 'White Polo', 'verified': true, 'verified_date': '2023-10-25'}, - {'id': 'black_cap', 'label': 'Black Cap', 'verified': false}, - ] - } - ]; - - String _searchQuery = ''; - - void _verifyItem(String workerId, String itemId, bool verified) { - setState(() { - final worker = _staff.firstWhere((w) => w['id'] == workerId); - final item = worker['itemsAttire'].firstWhere((i) => i['id'] == itemId); - item['verified'] = verified; - if (verified) { - item['verified_date'] = DateTime.now().toString().split(' ')[0]; - } else { - item.remove('verified_date'); - } - }); - } - - @override - Widget build(BuildContext context) { - final filteredWorkers = _staff.where((w) => - w['email'].toLowerCase().contains(_searchQuery.toLowerCase()) - ).toList(); - - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF64748B)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Verify Worker Attire', - style: TextStyle(color: Color(0xFF121826), fontSize: 18, fontWeight: FontWeight.bold), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(60), - child: Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), - child: TextField( - onChanged: (value) => setState(() => _searchQuery = value), - decoration: InputDecoration( - hintText: 'Search by worker email...', - prefixIcon: const Icon(LucideIcons.search, size: 20), - contentPadding: const EdgeInsets.symmetric(vertical: 0, horizontal: 16), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide(color: Color(0xFFE2E8F0)), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: const BorderSide(color: Color(0xFFE2E8F0)), - ), - filled: true, - fillColor: const Color(0xFFFAFBFC), - ), - ), - ), - ), - ), - body: filteredWorkers.isEmpty - ? const Center( - child: Text( - 'No workers with attire to verify', - style: TextStyle(color: Color(0xFF64748B)), - ), - ) - : ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: filteredWorkers.length, - itemBuilder: (context, index) { - final worker = filteredWorkers[index]; - final items = worker['itemsAttire'] as List; - final pendingItems = items.where((i) => !i['verified']).toList(); - final verifiedItems = items.where((i) => i['verified']).toList(); - - if (pendingItems.isEmpty && verifiedItems.isEmpty) return const SizedBox.shrink(); - - return Card( - margin: const EdgeInsets.only(bottom: 16), - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - side: const BorderSide(color: Color(0xFFE2E8F0)), - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - worker['email'], - style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - Text( - '${verifiedItems.length} verified · ${pendingItems.length} pending', - style: const TextStyle(color: Color(0xFF64748B), fontSize: 12), - ), - const SizedBox(height: 16), - ...pendingItems.map((item) => Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFFAFBFC), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: const Color(0xFFE2E8F0), - borderRadius: BorderRadius.circular(4), - ), - child: const Icon(LucideIcons.camera, color: Color(0xFF94A3B8)), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item['label'], - style: const TextStyle(fontWeight: FontWeight.w500), - ), - const Text( - 'Pending verification', - style: TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - ], - ), - ), - Row( - children: [ - InkWell( - onTap: () => _verifyItem(worker['id'], item['id'], false), // Reject acts same for now - child: Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: const Color(0xFFFEE2E2), - borderRadius: BorderRadius.circular(8), - ), - child: const Icon(LucideIcons.x, size: 16, color: Colors.red), - ), - ), - const SizedBox(width: 8), - InkWell( - onTap: () => _verifyItem(worker['id'], item['id'], true), - child: Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: const Color(0xFFD1FAE5), - borderRadius: BorderRadius.circular(8), - ), - child: const Icon(LucideIcons.check, size: 16, color: Colors.green), - ), - ), - ], - ), - ], - ), - )), - if (verifiedItems.isNotEmpty) - Theme( - data: Theme.of(context).copyWith(dividerColor: Colors.transparent), - child: ExpansionTile( - title: Text( - '${verifiedItems.length} verified items', - style: const TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - children: verifiedItems.map((item) => Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - children: [ - const Icon(LucideIcons.check, size: 12, color: Colors.green), - const SizedBox(width: 8), - Text( - '${item['label']} - ${item['verified_date']}', - style: const TextStyle(fontSize: 12, color: Color(0xFF64748B)), - ), - ], - ), - )).toList(), - ), - ), - ], - ), - ), - ); - }, - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/theme.dart b/apps/mobile/prototypes/client_mobile_application/lib/theme.dart deleted file mode 100644 index 2e5291b1..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/theme.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class AppColors { - static const Color krowBlue = Color(0xFF0A39DF); - static const Color krowYellow = Color(0xFFFFED4A); - static const Color krowCharcoal = Color(0xFF121826); - static const Color krowMuted = Color(0xFF6A7382); - static const Color krowBorder = Color(0xFFE3E6E9); - static const Color krowBackground = Color(0xFFFAFBFC); - - static const Color white = Colors.white; - static const Color black = Colors.black; -} - -class AppTheme { - static ThemeData get lightTheme { - return ThemeData( - useMaterial3: true, - scaffoldBackgroundColor: AppColors.krowBackground, - colorScheme: ColorScheme.fromSeed( - seedColor: AppColors.krowBlue, - primary: AppColors.krowBlue, - secondary: AppColors.krowYellow, - surface: AppColors.white, - background: AppColors.krowBackground, - ), - textTheme: GoogleFonts.instrumentSansTextTheme().apply( - bodyColor: AppColors.krowCharcoal, - displayColor: AppColors.krowCharcoal, - ), - appBarTheme: const AppBarTheme( - backgroundColor: AppColors.krowBackground, - elevation: 0, - iconTheme: IconThemeData(color: AppColors.krowCharcoal), - titleTextStyle: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/widgets/scaffold_with_nav_bar.dart b/apps/mobile/prototypes/client_mobile_application/lib/widgets/scaffold_with_nav_bar.dart deleted file mode 100644 index 1d2cba53..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/widgets/scaffold_with_nav_bar.dart +++ /dev/null @@ -1,137 +0,0 @@ -import 'dart:ui'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../theme.dart'; - -class ScaffoldWithNavBar extends StatelessWidget { - const ScaffoldWithNavBar({required this.navigationShell, super.key}); - - final StatefulNavigationShell navigationShell; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: navigationShell, - extendBody: true, - bottomNavigationBar: _buildBottomBar(context), - ); - } - - Widget _buildBottomBar(BuildContext context) { - bool isWorker = false; // This is the Client App - final activeColor = isWorker ? AppColors.krowBlue : AppColors.krowCharcoal; - final inactiveColor = const Color(0xFF8E8E93); - - return Stack( - clipBehavior: Clip.none, - children: [ - Positioned.fill( - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.85), - border: const Border( - top: BorderSide(color: Color.fromRGBO(0, 0, 0, 0.1)), - ), - ), - ), - ), - ), - ), - Container( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 8, - top: 16, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - _buildNavItem( - 0, - LucideIcons.calendar, - 'Coverage', - activeColor, - inactiveColor, - ), - _buildNavItem( - 1, - LucideIcons.dollarSign, - 'Billing', - activeColor, - inactiveColor, - ), - _buildNavItem( - 2, - LucideIcons.building2, - 'Home', - activeColor, - inactiveColor, - ), - _buildNavItem( - 3, - LucideIcons.fileText, - 'Orders', - activeColor, - inactiveColor, - ), - _buildNavItem( - 4, - LucideIcons.barChart3, - 'Reports', - activeColor, - inactiveColor, - ), - ], - ), - ), - ], - ); - } - - Widget _buildNavItem( - int index, - IconData icon, - String label, - Color activeColor, - Color inactiveColor, - ) { - final isSelected = navigationShell.currentIndex == index; - return Expanded( - child: GestureDetector( - onTap: () => _onTap(index), - behavior: HitTestBehavior.opaque, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Icon( - icon, - color: isSelected ? activeColor : inactiveColor, - size: 24, - ), - const SizedBox(height: 2), - Text( - label, - style: TextStyle( - color: isSelected ? activeColor : inactiveColor, - fontSize: 10, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ); - } - - void _onTap(int index) { - navigationShell.goBranch( - index, - initialLocation: index == navigationShell.currentIndex, - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/lib/widgets/web_mobile_frame.dart b/apps/mobile/prototypes/client_mobile_application/lib/widgets/web_mobile_frame.dart deleted file mode 100644 index 796eb5ba..00000000 --- a/apps/mobile/prototypes/client_mobile_application/lib/widgets/web_mobile_frame.dart +++ /dev/null @@ -1,271 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:google_fonts/google_fonts.dart'; - -/// A wrapper widget that renders the application inside an iPhone 14 Pro Max-like frame -/// specifically for Flutter Web. On other platforms, it simply returns the child. -class WebMobileFrame extends StatelessWidget { - final Widget child; - - const WebMobileFrame({super.key, required this.child}); - - @override - Widget build(BuildContext context) { - if (!kIsWeb) return child; - - return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData.dark(), - home: _WebFrameContent(child: child), - ); - } -} - -class _WebFrameContent extends StatefulWidget { - final Widget child; - const _WebFrameContent({required this.child}); - - @override - State<_WebFrameContent> createState() => _WebFrameContentState(); -} - -class _WebFrameContentState extends State<_WebFrameContent> { - Offset _cursorPosition = Offset.zero; - bool _isHovering = false; - - @override - Widget build(BuildContext context) { - // iPhone 14 Pro Max-ish dimensions (scaled for frame look) - const double frameWidth = 390 * 1.2; - const double frameHeight = 844 * 1.3; - const double borderRadius = 54.0; - const double borderThickness = 12.0; - - return Scaffold( - backgroundColor: const Color(0xFF121212), - body: MouseRegion( - cursor: SystemMouseCursors.none, - onHover: (event) { - setState(() { - _cursorPosition = event.position; - _isHovering = true; - }); - }, - onExit: (_) => setState(() => _isHovering = false), - child: Stack( - children: [ - // Logo and Title on the left (Web only) - Positioned( - left: 60, - top: 0, - bottom: 0, - child: Center( - child: Opacity( - opacity: 0.5, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.asset('assets/logo.png', width: 140), - const SizedBox(height: 12), - Text( - 'KROW Client \nApplication', - textAlign: TextAlign.left, - style: GoogleFonts.instrumentSans( - color: Colors.white, - fontSize: 28, - fontWeight: FontWeight.bold, - letterSpacing: -0.5, - ), - ), - const SizedBox(height: 4), - Container( - height: 2, - width: 40, - color: Colors.white.withOpacity(0.3), - ), - ], - ), - ), - ), - ), - - // Frame and Content - Center( - child: LayoutBuilder( - builder: (context, constraints) { - // Scale down if screen is too small - double scaleX = constraints.maxWidth / (frameWidth + 80); - double scaleY = constraints.maxHeight / (frameHeight + 80); - double scale = (scaleX < 1 || scaleY < 1) - ? (scaleX < scaleY ? scaleX : scaleY) - : 1.0; - - return Transform.scale( - scale: scale, - child: Container( - width: frameWidth, - height: frameHeight, - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(borderRadius), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.6), - blurRadius: 40, - spreadRadius: 10, - ), - ], - border: Border.all( - color: const Color(0xFF2C2C2C), - width: borderThickness, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular( - borderRadius - borderThickness, - ), - child: Stack( - children: [ - // The actual app + status bar - Column( - children: [ - // Mock iOS Status Bar - Container( - height: 48, - padding: const EdgeInsets.symmetric( - horizontal: 24, - ), - decoration: const BoxDecoration( - color: Color(0xFFF9F6EE), - border: Border( - bottom: BorderSide( - color: Color(0xFFEEEEEE), - width: 0.5, - ), - ), - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - // Time side - const SizedBox( - width: 80, - child: Text( - '3:12 PM', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.black54, - fontWeight: FontWeight.w700, - fontSize: 14, - letterSpacing: -0.2, - ), - ), - ), - // Status Icons side - SizedBox( - width: 80, - child: Row( - mainAxisAlignment: - MainAxisAlignment.end, - spacing: 12, - children: [ - const Icon( - FontAwesomeIcons.signal, - size: 12, - color: Colors.black54, - ), - const Icon( - FontAwesomeIcons.wifi, - size: 12, - color: Colors.black54, - ), - const Icon( - FontAwesomeIcons.batteryFull, - size: 12, - color: Colors.black54, - ), - ], - ), - ), - ], - ), - ), - // The main app content content - Expanded(child: widget.child), - ], - ), - - // Notch / Dynamic Island - Align( - alignment: Alignment.topCenter, - child: Padding( - padding: const EdgeInsets.only(top: 8), - child: Container( - width: 125, - height: 35, - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Container( - width: 8, - height: 8, - margin: const EdgeInsets.only( - right: 20, - ), - decoration: const BoxDecoration( - color: Color(0xFF0F0F0F), - shape: BoxShape.circle, - ), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ), - ); - }, - ), - ), - - // Custom Circle Cursor - if (_isHovering) - Positioned( - left: _cursorPosition.dx - 20, - top: _cursorPosition.dy - 20, - child: IgnorePointer( - child: ClipRRect( - borderRadius: BorderRadius.circular(25), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 2.5, sigmaY: 2.5), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.grey.withAlpha(50), - shape: BoxShape.circle, - border: Border.all(color: Colors.white, width: 1.5), - ), - ), - ), - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/linux/.gitignore b/apps/mobile/prototypes/client_mobile_application/linux/.gitignore deleted file mode 100644 index d3896c98..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/apps/mobile/prototypes/client_mobile_application/linux/CMakeLists.txt b/apps/mobile/prototypes/client_mobile_application/linux/CMakeLists.txt deleted file mode 100644 index b5ca6f2c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/CMakeLists.txt +++ /dev/null @@ -1,128 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "client_app_mvp") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.client_app_mvp") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/apps/mobile/prototypes/client_mobile_application/linux/flutter/CMakeLists.txt b/apps/mobile/prototypes/client_mobile_application/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd0164..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugin_registrant.cc b/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index f6f23bfe..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include - -void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); - url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); -} diff --git a/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugin_registrant.h b/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47b..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugins.cmake b/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugins.cmake deleted file mode 100644 index f16b4c34..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - url_launcher_linux -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/apps/mobile/prototypes/client_mobile_application/linux/runner/CMakeLists.txt b/apps/mobile/prototypes/client_mobile_application/linux/runner/CMakeLists.txt deleted file mode 100644 index e97dabc7..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/runner/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the application ID. -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/apps/mobile/prototypes/client_mobile_application/linux/runner/main.cc b/apps/mobile/prototypes/client_mobile_application/linux/runner/main.cc deleted file mode 100644 index e7c5c543..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/runner/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/apps/mobile/prototypes/client_mobile_application/linux/runner/my_application.cc b/apps/mobile/prototypes/client_mobile_application/linux/runner/my_application.cc deleted file mode 100644 index bcbdacaf..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/runner/my_application.cc +++ /dev/null @@ -1,148 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Called when first Flutter frame received. -static void first_frame_cb(MyApplication* self, FlView* view) { - gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); -} - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "client_app_mvp"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "client_app_mvp"); - } - - gtk_window_set_default_size(window, 1280, 720); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments( - project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - GdkRGBA background_color; - // Background defaults to black, override it here if necessary, e.g. #00000000 - // for transparent. - gdk_rgba_parse(&background_color, "#000000"); - fl_view_set_background_color(view, &background_color); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - // Show the window when Flutter renders. - // Requires the view to be realized so we can start rendering. - g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), - self); - gtk_widget_realize(GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, - gchar*** arguments, - int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GApplication::startup. -static void my_application_startup(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application startup. - - G_APPLICATION_CLASS(my_application_parent_class)->startup(application); -} - -// Implements GApplication::shutdown. -static void my_application_shutdown(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application shutdown. - - G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = - my_application_local_command_line; - G_APPLICATION_CLASS(klass)->startup = my_application_startup; - G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - // Set the program name to the application ID, which helps various systems - // like GTK and desktop environments map this running application to its - // corresponding .desktop file. This ensures better integration by allowing - // the application to be recognized beyond its binary name. - g_set_prgname(APPLICATION_ID); - - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, "flags", - G_APPLICATION_NON_UNIQUE, nullptr)); -} diff --git a/apps/mobile/prototypes/client_mobile_application/linux/runner/my_application.h b/apps/mobile/prototypes/client_mobile_application/linux/runner/my_application.h deleted file mode 100644 index db16367a..00000000 --- a/apps/mobile/prototypes/client_mobile_application/linux/runner/my_application.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, - my_application, - MY, - APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/.gitignore b/apps/mobile/prototypes/client_mobile_application/macos/.gitignore deleted file mode 100644 index 746adbb6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Flutter/Flutter-Debug.xcconfig b/apps/mobile/prototypes/client_mobile_application/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Flutter/Flutter-Release.xcconfig b/apps/mobile/prototypes/client_mobile_application/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d15..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Flutter/GeneratedPluginRegistrant.swift b/apps/mobile/prototypes/client_mobile_application/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index 4f908931..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import firebase_core -import path_provider_foundation -import url_launcher_macos - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) -} diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Podfile b/apps/mobile/prototypes/client_mobile_application/macos/Podfile deleted file mode 100644 index ff5ddb3b..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Podfile +++ /dev/null @@ -1,42 +0,0 @@ -platform :osx, '10.15' - -# 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', 'ephemeral', '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 Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/project.pbxproj b/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 7a9ccf1c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,705 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* client_app_mvp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "client_app_mvp.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* client_app_mvp.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* client_app_mvp.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/client_app_mvp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/client_app_mvp"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/client_app_mvp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/client_app_mvp"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/client_app_mvp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/client_app_mvp"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 732dbe0c..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcworkspace/contents.xcworkspacedata b/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/AppDelegate.swift b/apps/mobile/prototypes/client_mobile_application/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c17614..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa4..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cf..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Base.lproj/MainMenu.xib b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/AppInfo.xcconfig b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 9932ad62..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = client_app_mvp - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Debug.xcconfig b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Release.xcconfig b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Warnings.xcconfig b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/DebugProfile.entitlements b/apps/mobile/prototypes/client_mobile_application/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Info.plist b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/MainFlutterWindow.swift b/apps/mobile/prototypes/client_mobile_application/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb2..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Release.entitlements b/apps/mobile/prototypes/client_mobile_application/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a4..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/apps/mobile/prototypes/client_mobile_application/macos/RunnerTests/RunnerTests.swift b/apps/mobile/prototypes/client_mobile_application/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 61f3bd1f..00000000 --- a/apps/mobile/prototypes/client_mobile_application/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Cocoa -import FlutterMacOS -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/apps/mobile/prototypes/client_mobile_application/pubspec.lock b/apps/mobile/prototypes/client_mobile_application/pubspec.lock deleted file mode 100644 index 377d9419..00000000 --- a/apps/mobile/prototypes/client_mobile_application/pubspec.lock +++ /dev/null @@ -1,866 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d - url: "https://pub.dev" - source: hosted - version: "91.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 - url: "https://pub.dev" - source: hosted - version: "8.4.1" - archive: - dependency: transitive - description: - name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.dev" - source: hosted - version: "4.0.7" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.dev" - source: hosted - version: "2.0.4" - cli_config: - dependency: transitive - description: - name: cli_config - sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec - url: "https://pub.dev" - source: hosted - version: "0.2.0" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" - url: "https://pub.dev" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" - source: hosted - version: "3.0.7" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - equatable: - dependency: transitive - description: - name: equatable - sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" - url: "https://pub.dev" - source: hosted - version: "2.0.7" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - sha256: "1f2dfd9f535d81f8b06d7a50ecda6eac1e6922191ed42e09ca2c84bd2288927c" - url: "https://pub.dev" - source: hosted - version: "4.2.1" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 - url: "https://pub.dev" - source: hosted - version: "6.0.2" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: ff18fabb0ad0ed3595d2f2c85007ecc794aadecdff5b3bb1460b7ee47cded398 - url: "https://pub.dev" - source: hosted - version: "3.3.0" - fl_chart: - dependency: "direct main" - description: - name: fl_chart - sha256: "7ca9a40f4eb85949190e54087be8b4d6ac09dc4c54238d782a34cf1f7c011de9" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_launcher_icons: - dependency: "direct dev" - description: - name: flutter_launcher_icons - sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" - url: "https://pub.dev" - source: hosted - version: "0.14.4" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_riverpod: - dependency: "direct main" - description: - name: flutter_riverpod - sha256: "9e2d6907f12cc7d23a846847615941bddee8709bf2bfd274acdf5e80bcf22fde" - url: "https://pub.dev" - source: hosted - version: "3.0.3" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - font_awesome_flutter: - dependency: "direct main" - description: - name: font_awesome_flutter - sha256: b9011df3a1fa02993630b8fb83526368cf2206a711259830325bab2f1d2a4eb0 - url: "https://pub.dev" - source: hosted - version: "10.12.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: c92d18e1fe994cb06d48aa786c46b142a5633067e8297cff6b5a3ac742620104 - url: "https://pub.dev" - source: hosted - version: "17.0.0" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055 - url: "https://pub.dev" - source: hosted - version: "6.3.3" - http: - dependency: transitive - description: - name: http - sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image: - dependency: transitive - description: - name: image - sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" - url: "https://pub.dev" - source: hosted - version: "4.5.4" - intl: - dependency: "direct main" - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" - source: hosted - version: "0.7.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - lucide_icons: - dependency: "direct main" - description: - name: lucide_icons - sha256: ad24d0fd65707e48add30bebada7d90bff2a1bba0a72d6e9b19d44246b0e83c4 - url: "https://pub.dev" - source: hosted - version: "0.257.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.dev" - source: hosted - version: "2.2.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" - source: hosted - version: "2.2.22" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" - url: "https://pub.dev" - source: hosted - version: "2.5.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" - url: "https://pub.dev" - source: hosted - version: "7.0.1" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pool: - dependency: transitive - description: - name: pool - sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" - url: "https://pub.dev" - source: hosted - version: "1.5.2" - posix: - dependency: transitive - description: - name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.dev" - source: hosted - version: "6.0.3" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - riverpod: - dependency: transitive - description: - name: riverpod - sha256: c406de02bff19d920b832bddfb8283548bfa05ce41c59afba57ce643e116aa59 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" - url: "https://pub.dev" - source: hosted - version: "0.10.13" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - state_notifier: - dependency: transitive - description: - name: state_notifier - sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb - url: "https://pub.dev" - source: hosted - version: "1.0.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test: - dependency: transitive - description: - name: test - sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" - url: "https://pub.dev" - source: hosted - version: "1.26.3" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - test_core: - dependency: transitive - description: - name: test_core - sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" - url: "https://pub.dev" - source: hosted - version: "0.6.12" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" - source: hosted - version: "6.3.28" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: cfde38aa257dae62ffe79c87fab20165dfdf6988c1d31b58ebf59b9106062aad - url: "https://pub.dev" - source: hosted - version: "6.3.6" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" - watcher: - dependency: transitive - description: - name: watcher - sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a" - url: "https://pub.dev" - source: hosted - version: "1.1.4" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" - source: hosted - version: "6.6.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.35.0" diff --git a/apps/mobile/prototypes/client_mobile_application/pubspec.yaml b/apps/mobile/prototypes/client_mobile_application/pubspec.yaml deleted file mode 100644 index 0f69b66a..00000000 --- a/apps/mobile/prototypes/client_mobile_application/pubspec.yaml +++ /dev/null @@ -1,103 +0,0 @@ -name: client_app_mvp -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+6 - -environment: - sdk: ^3.10.0 - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - go_router: ^17.0.0 - flutter_riverpod: ^3.0.3 - google_fonts: ^6.3.3 - intl: ^0.20.2 - lucide_icons: ^0.257.0 - flutter_svg: ^2.2.3 - fl_chart: ^1.1.1 - firebase_core: ^4.2.1 - url_launcher: ^6.3.2 - font_awesome_flutter: ^10.12.0 - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^6.0.0 - flutter_launcher_icons: ^0.14.4 - -flutter_launcher_icons: - android: "launcher_icon" - ios: true - image_path: "assets/logo.png" - remove_alpha_ios: true - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - - assets: - - assets/logo.png - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/apps/mobile/prototypes/client_mobile_application/test/widget_test.dart b/apps/mobile/prototypes/client_mobile_application/test/widget_test.dart deleted file mode 100644 index 5516c273..00000000 --- a/apps/mobile/prototypes/client_mobile_application/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:client_app_mvp/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const AppRoot()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/apps/mobile/prototypes/client_mobile_application/web/favicon.png b/apps/mobile/prototypes/client_mobile_application/web/favicon.png deleted file mode 100644 index 8aaa46ac..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/web/favicon.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-192.png b/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-192.png deleted file mode 100644 index b749bfef..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-192.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-512.png b/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48d..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-512.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-maskable-192.png b/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-maskable-512.png b/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c5669..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/web/index.html b/apps/mobile/prototypes/client_mobile_application/web/index.html deleted file mode 100644 index d0a2ce87..00000000 --- a/apps/mobile/prototypes/client_mobile_application/web/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - client_app_mvp - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/web/manifest.json b/apps/mobile/prototypes/client_mobile_application/web/manifest.json deleted file mode 100644 index 14ca16c9..00000000 --- a/apps/mobile/prototypes/client_mobile_application/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "client_app_mvp", - "short_name": "client_app_mvp", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/apps/mobile/prototypes/client_mobile_application/windows/.gitignore b/apps/mobile/prototypes/client_mobile_application/windows/.gitignore deleted file mode 100644 index d492d0d9..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/apps/mobile/prototypes/client_mobile_application/windows/CMakeLists.txt b/apps/mobile/prototypes/client_mobile_application/windows/CMakeLists.txt deleted file mode 100644 index 369636d4..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/CMakeLists.txt +++ /dev/null @@ -1,108 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(client_app_mvp LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "client_app_mvp") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(VERSION 3.14...3.25) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/apps/mobile/prototypes/client_mobile_application/windows/flutter/CMakeLists.txt b/apps/mobile/prototypes/client_mobile_application/windows/flutter/CMakeLists.txt deleted file mode 100644 index 903f4899..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# Set fallback configurations for older versions of the flutter tool. -if (NOT DEFINED FLUTTER_TARGET_PLATFORM) - set(FLUTTER_TARGET_PLATFORM "windows-x64") -endif() - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - ${FLUTTER_TARGET_PLATFORM} $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugin_registrant.cc b/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index ec8e8d45..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,17 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - FirebaseCorePluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); - UrlLauncherWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("UrlLauncherWindows")); -} diff --git a/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugin_registrant.h b/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugins.cmake b/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugins.cmake deleted file mode 100644 index 02d26c31..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - firebase_core - url_launcher_windows -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/CMakeLists.txt b/apps/mobile/prototypes/client_mobile_application/windows/runner/CMakeLists.txt deleted file mode 100644 index 394917c0..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/Runner.rc b/apps/mobile/prototypes/client_mobile_application/windows/runner/Runner.rc deleted file mode 100644 index c6f91c08..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "client_app_mvp" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "client_app_mvp" "\0" - VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "client_app_mvp.exe" "\0" - VALUE "ProductName", "client_app_mvp" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/flutter_window.cpp b/apps/mobile/prototypes/client_mobile_application/windows/runner/flutter_window.cpp deleted file mode 100644 index 955ee303..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - // Flutter can complete the first frame before the "show window" callback is - // registered. The following call ensures a frame is pending to ensure the - // window is shown. It is a no-op if the first frame hasn't completed yet. - flutter_controller_->ForceRedraw(); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/flutter_window.h b/apps/mobile/prototypes/client_mobile_application/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652f..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/main.cpp b/apps/mobile/prototypes/client_mobile_application/windows/runner/main.cpp deleted file mode 100644 index 0ccff5c2..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"client_app_mvp", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/resource.h b/apps/mobile/prototypes/client_mobile_application/windows/runner/resource.h deleted file mode 100644 index 66a65d1e..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/resources/app_icon.ico b/apps/mobile/prototypes/client_mobile_application/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20ca..00000000 Binary files a/apps/mobile/prototypes/client_mobile_application/windows/runner/resources/app_icon.ico and /dev/null differ diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/runner.exe.manifest b/apps/mobile/prototypes/client_mobile_application/windows/runner/runner.exe.manifest deleted file mode 100644 index 153653e8..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,14 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/utils.cpp b/apps/mobile/prototypes/client_mobile_application/windows/runner/utils.cpp deleted file mode 100644 index 3a0b4651..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/utils.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - unsigned int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length == 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/utils.h b/apps/mobile/prototypes/client_mobile_application/windows/runner/utils.h deleted file mode 100644 index 3879d547..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/win32_window.cpp b/apps/mobile/prototypes/client_mobile_application/windows/runner/win32_window.cpp deleted file mode 100644 index 60608d0f..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/win32_window.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} diff --git a/apps/mobile/prototypes/client_mobile_application/windows/runner/win32_window.h b/apps/mobile/prototypes/client_mobile_application/windows/runner/win32_window.h deleted file mode 100644 index e901dde6..00000000 --- a/apps/mobile/prototypes/client_mobile_application/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/apps/mobile/prototypes/staff_mobile_application/.gitignore b/apps/mobile/prototypes/staff_mobile_application/.gitignore deleted file mode 100644 index 3820a95c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ -/coverage/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/apps/mobile/prototypes/staff_mobile_application/.metadata b/apps/mobile/prototypes/staff_mobile_application/.metadata deleted file mode 100644 index 2c6187b3..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "b45fa18946ecc2d9b4009952c636ba7e2ffbb787" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: android - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: ios - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: linux - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: macos - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: web - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - platform: windows - create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/apps/mobile/prototypes/staff_mobile_application/README.md b/apps/mobile/prototypes/staff_mobile_application/README.md deleted file mode 100644 index 240238ed..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# staff_app_mvp - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/apps/mobile/prototypes/staff_mobile_application/analysis_options.yaml b/apps/mobile/prototypes/staff_mobile_application/analysis_options.yaml deleted file mode 100644 index 0d290213..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# 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/apps/mobile/prototypes/staff_mobile_application/android/.gitignore b/apps/mobile/prototypes/staff_mobile_application/android/.gitignore deleted file mode 100644 index be3943c9..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java -.cxx/ - -# Remember to never publicly share your keystore. -# See https://flutter.dev/to/reference-keystore -key.properties -**/*.keystore -**/*.jks diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/29a493751_PNG3Krow.png b/apps/mobile/prototypes/staff_mobile_application/android/app/29a493751_PNG3Krow.png deleted file mode 100644 index ef04350b..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/android/app/29a493751_PNG3Krow.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/build.gradle.kts b/apps/mobile/prototypes/staff_mobile_application/android/app/build.gradle.kts deleted file mode 100644 index c25c559e..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/build.gradle.kts +++ /dev/null @@ -1,45 +0,0 @@ -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") -} - -android { - namespace = "com.example.staff_app_mvp" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.staff_app_mvp" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName - } - - 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") - } - } -} - -flutter { - source = "../.." -} diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/google-services.json b/apps/mobile/prototypes/staff_mobile_application/android/app/google-services.json deleted file mode 100644 index ab8e078c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/google-services.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "project_info": { - "project_number": "717206318340", - "project_id": "krow-apps", - "storage_bucket": "krow-apps.firebasestorage.app" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:717206318340:android:d3eac8c3774905e08af451", - "android_client_info": { - "package_name": "com.example.staff_app_mvp" - } - }, - "oauth_client": [ - { - "client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com", - "client_type": 3 - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/debug/AndroidManifest.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/AndroidManifest.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 02a7e068..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/kotlin/com/example/staff_app_mvp/MainActivity.kt b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/kotlin/com/example/staff_app_mvp/MainActivity.kt deleted file mode 100644 index 861d0ce3..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/kotlin/com/example/staff_app_mvp/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.staff_app_mvp - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity : FlutterActivity() diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/drawable-v21/launch_background.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/drawable/launch_background.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 3091831a..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 9fac3fb8..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 7bd61725..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index c81445eb..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 6fa64c69..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/values-night/styles.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be7..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/values/styles.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef880..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/app/src/profile/AndroidManifest.xml b/apps/mobile/prototypes/staff_mobile_application/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/android/build.gradle.kts b/apps/mobile/prototypes/staff_mobile_application/android/build.gradle.kts deleted file mode 100644 index dbee657b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/build.gradle.kts +++ /dev/null @@ -1,24 +0,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/apps/mobile/prototypes/staff_mobile_application/android/gradle.properties b/apps/mobile/prototypes/staff_mobile_application/android/gradle.properties deleted file mode 100644 index fbee1d8c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true diff --git a/apps/mobile/prototypes/staff_mobile_application/android/gradle/wrapper/gradle-wrapper.properties b/apps/mobile/prototypes/staff_mobile_application/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e4ef43fb..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/apps/mobile/prototypes/staff_mobile_application/android/settings.gradle.kts b/apps/mobile/prototypes/staff_mobile_application/android/settings.gradle.kts deleted file mode 100644 index e4e86fb6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/android/settings.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -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.11.1" apply false - id("org.jetbrains.kotlin.android") version "2.2.20" apply false - id("com.google.gms.google-services") version "4.4.2" apply false -} - -include(":app") diff --git a/apps/mobile/prototypes/staff_mobile_application/assets/logo.png b/apps/mobile/prototypes/staff_mobile_application/assets/logo.png deleted file mode 100644 index b1dd25b7..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/assets/logo.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/comparation_v2_v3.md b/apps/mobile/prototypes/staff_mobile_application/comparation_v2_v3.md deleted file mode 100644 index 48e7b853..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/comparation_v2_v3.md +++ /dev/null @@ -1,304 +0,0 @@ -# Comparación de Estructura de Datos: v2 vs. v3 (Análisis Detallado) - -Este documento detalla las diferencias y similitudes en el uso de `Map` y `List>` entre la versión 2 (descrita en `mock_staff_app_v2.md`) y la versión 3 (código actual). - -## Resumen Ejecutivo - -El análisis de la v3 revela dos puntos clave: -1. **Persistencia del uso de `Map`**: La gran mayoría de las estructuras de datos para mocks y estado de la UI siguen siendo `Map`, muy similares a las de la v2. La inconsistencia y duplicación de datos entre diferentes pantallas sigue siendo un problema. -2. **Inicio de la Refactorización a Modelos**: La introducción de la clase `Shift` en `lib/models/shift.dart` y su uso en `clock_in_screen.dart` marca el primer paso concreto para abandonar el patrón de `Map` en favor de objetos fuertemente tipados, tal como se recomendó. - -Este informe primero catalogará todas las estructuras `Map` encontradas en la v3 y luego las comparará con el análisis de la v2. - ---- - -## 1. Análisis de Estructuras `Map` en v3 - -A continuación se listan las estructuras encontradas en el código actual del proyecto. - -### `lib/screens/auth/profile_setup_screen.dart` - -1. **Variable**: `static const List> _steps` - * **Propósito**: Define los pasos del wizard de creación de perfil. - * **Estructura de cada elemento**: - ```json - { - "id": String, - "title": String, - "icon": IconData - } - ``` - -### `lib/screens/worker/availability_screen.dart` - -1. **Variable**: `final List> _timeSlots` - * **Propósito**: Define las propiedades de los rangos horarios seleccionables (mañana, tarde, noche). - * **Estructura de cada elemento**: - ```json - { - "id": String, - "label": String, - "time": String, - "icon": IconData, - "bg": Color, - "iconColor": Color - } - ``` - -### `lib/screens/worker/benefits_screen.dart` - -1. **Variable**: `final List> _benefitsData` - * **Propósito**: Mock data para los beneficios del trabajador. - * **Estructura de cada elemento**: - ```json - { - "id": String, - "title": String, - "current": int, - "total": int, - "color": Color, - "description": String, - "history": List>, // Anidado - "requestLabel": String, - "notice": String? - } - ``` - * **Estructura anidada de `history`**: - ```json - { - "date": String, - "status": String - } - ``` -2. **Parámetro de Función**: `void _handleRequest(Map benefit)` - * **Propósito**: Maneja la acción de solicitar un beneficio. - * **Estructura**: La misma que un elemento de `_benefitsData`. -3. **Parámetro de Widget**: `final Map benefit` (en `_BenefitCard`) - * **Propósito**: Pasa los datos de un beneficio al widget de tarjeta. - * **Estructura**: La misma que un elemento de `_benefitsData`. - -### `lib/screens/worker/clock_in_screen.dart` - -1. **Variable**: `final List> _recentActivity` - * **Propósito**: Mock data para la lista de actividad reciente de fichajes. - * **Estructura de cada elemento**: - ```json - { - "date": DateTime, - "start": String, - "end": String, - "hours": String - } - ``` - -### `lib/screens/worker/earnings_screen.dart` - -1. **Variable**: `final List> _recentPayments` - * **Propósito**: Mock data para la lista de pagos recientes. - * **Estructura de cada elemento**: - ```json - { - "date": String, - "amount": double, - "shifts": int, - "status": String - } - ``` - -### `lib/screens/worker/payments_screen.dart` - -1. **Variable**: `final List> _recentPayments` - * **Propósito**: Mock data para el historial de pagos. - * **Estructura de cada elemento**: - ```json - { - "date": String, - "title": String, - "location": String, - "address": String, - "workedTime": String, - "amount": double, - "status": String, - "hours": int, - "rate": int // Inconsistencia, debería ser double - } - ``` - -### `lib/screens/worker/worker_profile_screen.dart` - -1. **Variable**: `final Map _user` - * **Propósito**: Mock data para la información básica del usuario. - * **Estructura**: - ```json - { - "full_name": String, - "email": String - } - ``` -2. **Variable**: `final Map _profile` - * **Propósito**: Mock data para las estadísticas del perfil del trabajador. - * **Estructura**: - ```json - { - "level": String, - "photo_url": String?, - "total_shifts": int, - "average_rating": double, - "on_time_rate": int, - "no_show_count": int, - "cancellation_count": int, - "reliability_score": int, - "phone": String, - "skills": List - } - ``` - -### `lib/screens/worker/worker_profile/compliance/certificates_screen.dart` - -1. **Variable**: `final List> _certificates` - * **Propósito**: Mock data para los certificados de cumplimiento. - * **Estructura de cada elemento**: - ```json - { - "id": String, - "name": String, - "icon": IconData, - "color": Color, - "description": String, - "status": String, - "expiry": String? // ISO 8601 - } - ``` -2. **Parámetro de Función/Widget**: Se usa `Map cert` en `_buildCertificateCard` y `_showUploadModal`. - -### `lib/screens/worker/worker_profile/level_up/krow_university_screen.dart` - -1. **Variable**: `final Map _profile` - * **Propósito**: Mock data para el perfil dentro de Krow University. **Nota: Es inconsistente con el `_profile` de `worker_profile_screen.dart`**. - * **Estructura**: - ```json - { - "level": String, - "xp": int, - "badges": List - } - ``` -2. **Variable**: `final List> _levels` - * **Propósito**: Define los distintos niveles de Krower. - * **Estructura de cada elemento**: - ```json - { - "name": String, - "xpRequired": int, - "icon": IconData, - "colors": List - } - ``` -3. **Variable**: `final List> _categories` - * **Propósito**: Define las categorías de los cursos. - * **Estructura de cada elemento**: - ```json - { - "id": String, - "label": String, - "icon": IconData - } - ``` -4. **Variable**: `final List> _courses` - * **Propósito**: Mock data para la lista de cursos. - * **Estructura de cada elemento**: - ```json - { - "id": String, - "title": String, - "description": String, - "category": String, - "duration_minutes": int, - "xp_reward": int, - "level_required": String, - "is_certification": bool, - "progress_percent": int, - "completed": bool - } - ``` - -### `lib/services/mock_service.dart` - -1. **Parámetro de Función**: `Future createWorkerProfile(Map data)` - * **Propósito**: Simula la creación de un perfil. - * **Estructura esperada (inferida de `profile_setup_screen.dart`)**: - ```json - { - "full_name": String, - "bio": String, - "preferred_locations": List, - "max_distance_miles": double, - "skills": List, - "industries": List - } - ``` - -### `lib/widgets/shift_card.dart` - -1. **Tipo de Retorno de Función**: `Map _calculateDuration()` - * **Propósito**: Calcula la duración de un turno. - * **Estructura devuelta**: - ```json - { - "hours": int, - "breakTime": String - } - ``` - ---- - -## 2. Comparación v2 vs. v3 - -### A. Nuevas Estructuras en v3 -- `lib/screens/worker/worker_profile/level_up/krow_university_screen.dart`: - - `_levels`: Define los niveles de Krower. No estaba en el análisis v2. - - `_profile`: Una nueva versión **inconsistente** del perfil del usuario, específica para esta pantalla. -- `lib/screens/worker/earnings_screen.dart`: - - `_recentPayments`: Una nueva lista de pagos, diferente en estructura a la de `payments_screen.dart`. - -### B. Estructuras Sin Cambios (o muy similares) -Las siguientes estructuras son prácticamente idénticas a las descritas en el análisis de la v2: -- `_steps` en `profile_setup_screen.dart`. -- `_timeSlots` en `availability_screen.dart`. -- `_benefitsData` en `benefits_screen.dart`. -- `_user` y `_profile` en `worker_profile_screen.dart`. -- `_certificates` en `certificates_screen.dart`. -- El parámetro de `createWorkerProfile` en `mock_service.dart`. -- El retorno de `_calculateDuration` en `shift_card.dart`. -- `_recentActivity` en `clock_in_screen.dart`. -- `_recentPayments` en `payments_screen.dart` (aunque es similar a la de `earnings_screen`, su estructura es más detallada y consistente con v2). - -### C. Estructuras Modificadas o con Nuevos Hallazgos -- `krow_university_screen.dart` (`_courses`, `_categories`): El análisis de la v2 mencionaba este archivo pero no detallaba estas estructuras. Ahora están formalmente documentadas. -- La **inconsistencia** del objeto `_profile` es más evidente ahora, con dos versiones diferentes en `worker_profile_screen.dart` y `krow_university_screen.dart`. - -### D. Estructuras Eliminadas / Reemplazadas -Este es el cambio más importante: - -- **Reemplazo conceptual de `Map` por Clases**: El uso de `Map` para representar un turno (`shift`) ha sido reemplazado por una clase. - - **ANTES (v2)**: Archivos como `payments_screen.dart` o `time_card_screen.dart` tenían su propia definición de `Map` para un turno/pago. - - **AHORA (v3)**: Se ha introducido `lib/models/shift.dart` con las clases `Shift` y `ShiftManager`. - - **EVIDENCIA**: El archivo `lib/screens/worker/clock_in_screen.dart` ya no usa un `Map` para el turno del día, sino una instancia de la nueva clase: - ```dart - final Shift? _todayShift = Shift(...); - ``` - Esto demuestra el inicio de la migración hacia modelos tipados. - ---- - -## Conclusión y Recomendación - -La v3 del proyecto sigue dependiendo masivamente de `Map` para datos de mock y estado, con casi todas las estructuras de la v2 todavía presentes. Las **inconsistencias** (ej. múltiples versiones de `_profile`, `_recentPayments`) siguen siendo un riesgo técnico. - -Sin embargo, la introducción de `Shift` y `ShiftManager` es un **avance arquitectónico muy positivo**. Muestra la dirección correcta para el proyecto. - -**Mi recomendación sigue siendo la misma, pero ahora con un plan de acción más claro:** -1. **Priorizar la unificación de `Profile`/`User`**: Crear una clase `UserProfile` en `lib/models/` que unifique las diferentes versiones de `_profile` y `_user`. -2. **Migrar `_recentPayments` y `_timesheets`**: Refactorizar `payments_screen.dart`, `earnings_screen.dart` y `time_card_screen.dart` para que usen `List` o una nueva clase `Payment` si es necesario, en lugar de `List>`. -3. **Continuar la Modelización**: Progresivamente, convertir las demás estructuras de `Map` (`Benefit`, `Certificate`, `Course`, etc.) en sus propias clases dentro de `lib/models/`. -4. **Limpiar Mocks**: Una vez que los modelos existan, los mocks deben ser instancias de estas clases, no `Map`s, para garantizar la consistencia en toda la aplicación. \ No newline at end of file diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/.gitignore b/apps/mobile/prototypes/staff_mobile_application/ios/.gitignore deleted file mode 100644 index 7a7f9873..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/AppFrameworkInfo.plist b/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 1dc6cf76..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 13.0 - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/Debug.xcconfig b/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/Release.xcconfig b/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bfe..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Podfile b/apps/mobile/prototypes/staff_mobile_application/ios/Podfile deleted file mode 100644 index 620e46eb..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -# Uncomment this line to define a global platform for your project -# platform :ios, '13.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! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.pbxproj b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index 12b34513..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,728 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - 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 */; }; - 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 */; }; - A6F5EE189BF639628AE45C3C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B13CCDB5FD8CEB4F8FFB43B /* Pods_RunnerTests.framework */; }; - D5F26222A5E50B6A60DA39DA /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0B9CCEC15DE23E58DC42451 /* Pods_Runner.framework */; }; -/* 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; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 039A2FCBC314380B54033007 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 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 = ""; }; - 2CC144E0143B4CAAD8949124 /* 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 = ""; }; - 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; }; - 3B13CCDB5FD8CEB4F8FFB43B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 6D58F7CBA805D9F84D2DDB73 /* 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 = ""; }; - 6D7385FFF09B0C6116FEC86A /* 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 = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 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 = ""; }; - B0B9CCEC15DE23E58DC42451 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - C08B5E216D105790DF6FB837 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - CF7A185B9A21B91B0DE7D158 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 6F3F2623D6016F80292A992F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - A6F5EE189BF639628AE45C3C /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D5F26222A5E50B6A60DA39DA /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 384E97F604A1C0D9D7F8ACFD /* Frameworks */ = { - isa = PBXGroup; - children = ( - B0B9CCEC15DE23E58DC42451 /* Pods_Runner.framework */, - 3B13CCDB5FD8CEB4F8FFB43B /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 9431EBE7EB5D5EB6B71540CB /* Pods */ = { - isa = PBXGroup; - children = ( - 2CC144E0143B4CAAD8949124 /* Pods-Runner.debug.xcconfig */, - 6D58F7CBA805D9F84D2DDB73 /* Pods-Runner.release.xcconfig */, - 6D7385FFF09B0C6116FEC86A /* Pods-Runner.profile.xcconfig */, - C08B5E216D105790DF6FB837 /* Pods-RunnerTests.debug.xcconfig */, - CF7A185B9A21B91B0DE7D158 /* Pods-RunnerTests.release.xcconfig */, - 039A2FCBC314380B54033007 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - 9431EBE7EB5D5EB6B71540CB /* Pods */, - 384E97F604A1C0D9D7F8ACFD /* Frameworks */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - CE9689C1E92E6C2367B60EBA /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - 6F3F2623D6016F80292A992F /* Frameworks */, - ); - 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 = ( - 9CBB0946A0D01F90169EAEE5 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 63412035F5A4F70543904256 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - 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; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 63412035F5A4F70543904256 /* [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; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - 9CBB0946A0D01F90169EAEE5 /* [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; - }; - CE9689C1E92E6C2367B60EBA /* [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-RunnerTests-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; - }; -/* 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; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* 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; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - 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++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - 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; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = C08B5E216D105790DF6FB837 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp.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; - baseConfigurationReference = CF7A185B9A21B91B0DE7D158 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp.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; - baseConfigurationReference = 039A2FCBC314380B54033007 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp.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++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - 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; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - 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++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - 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; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* 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 = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index e3773d42..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/contents.xcworkspacedata b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc14..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/AppDelegate.swift b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/AppDelegate.swift deleted file mode 100644 index 62666446..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Flutter -import UIKit - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d0d98aa1..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1 +0,0 @@ -{"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/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index a4e27cb8..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index e8a0e98e..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 31adf542..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index ab2a4d32..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index b4fd03f9..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index 60876d70..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 2222f2a6..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 31adf542..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index e1698c3e..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 2c6c319c..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png deleted file mode 100644 index 28518ca7..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png deleted file mode 100644 index da7ece04..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index 2aba981b..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index 2f9542fc..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 2c6c319c..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 416b3c4b..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png deleted file mode 100644 index 1ef96663..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png deleted file mode 100644 index d511631f..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index b44e41be..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 42aeffe3..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 9d95935f..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Base.lproj/LaunchScreen.storyboard b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Base.lproj/Main.storyboard b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Info.plist b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Info.plist deleted file mode 100644 index 3dd22eac..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Info.plist +++ /dev/null @@ -1,49 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Krow Staff App MVP - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - staff_app_mvp - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Runner-Bridging-Header.h b/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/apps/mobile/prototypes/staff_mobile_application/ios/RunnerTests/RunnerTests.swift b/apps/mobile/prototypes/staff_mobile_application/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b1..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -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/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/config.json b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/config.json deleted file mode 100644 index e37ed06f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "A set of guides for interacting with the generated firebase dataconnect sdk", - "mcpServers": { - "firebase": { - "command": "npx", - "args": ["-y", "firebase-tools@latest", "experimental:mcp"] - } - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/setup.md b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/setup.md deleted file mode 100644 index 4a3737fe..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/setup.md +++ /dev/null @@ -1,15 +0,0 @@ -# Setup - -This guide will walk you through setting up your environment to use the Firebase Data Connect SDK. Mostly using -documentation listed [here](https://firebase.google.com/docs/flutter/setup?platform=ios#install-cli-tools). - -1. Make sure you have the latest Firebase CLI tools installed. Follow the instructions [here](https://firebase.google.com/docs/cli#setup_update_cli) to install. -2. Log into your Firebase account: -```sh -firebase login -``` -3. Install the FlutterFire CLI by running the following command from any directory: -```sh -dart pub global activate flutterfire_cli -``` -4. Make sure the user has initialized Firebase already based on the instructions [here](https://firebase.google.com/docs/flutter/setup?platform=ios#initialize-firebase). diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/usage.md b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/usage.md deleted file mode 100644 index 28407bc2..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/.guides/usage.md +++ /dev/null @@ -1,31 +0,0 @@ -# Basic Usage - -```dart -ExampleConnector.instance.CreateMovie(createMovieVariables).execute(); -ExampleConnector.instance.UpsertUser(upsertUserVariables).execute(); -ExampleConnector.instance.AddReview(addReviewVariables).execute(); -ExampleConnector.instance.DeleteReview(deleteReviewVariables).execute(); -ExampleConnector.instance.ListMovies().execute(); -ExampleConnector.instance.ListUsers().execute(); -ExampleConnector.instance.ListUserReviews().execute(); -ExampleConnector.instance.GetMovieById(getMovieByIdVariables).execute(); -ExampleConnector.instance.SearchMovie(searchMovieVariables).execute(); - -``` - -## Optional Fields - -Some operations may have optional fields. In these cases, the Flutter SDK exposes a builder method, and will have to be set separately. - -Optional fields can be discovered based on classes that have `Optional` object types. - -This is an example of a mutation with an optional field: - -```dart -await ExampleConnector.instance.SearchMovie({ ... }) -.titleInput(...) -.execute(); -``` - -Note: the above example is a mutation, but the same logic applies to query operations as well. Additionally, `createMovie` is an example, and may not be available to the user. - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/README.md b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/README.md deleted file mode 100644 index 2104decc..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/README.md +++ /dev/null @@ -1,446 +0,0 @@ -# dataconnect_generated SDK - -## Installation -```sh -flutter pub get firebase_data_connect -flutterfire configure -``` -For more information, see [Flutter for Firebase installation documentation](https://firebase.google.com/docs/data-connect/flutter-sdk#use-core). - -## Data Connect instance -Each connector creates a static class, with an instance of the `DataConnect` class that can be used to connect to your Data Connect backend and call operations. - -### Connecting to the emulator - -```dart -String host = 'localhost'; // or your host name -int port = 9399; // or your port number -ExampleConnector.instance.dataConnect.useDataConnectEmulator(host, port); -``` - -You can also call queries and mutations by using the connector class. -## Queries - -### ListMovies -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.listMovies().execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.listMovies(); -ListMoviesData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.listMovies().ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### ListUsers -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.listUsers().execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.listUsers(); -ListUsersData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.listUsers().ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### ListUserReviews -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.listUserReviews().execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.listUserReviews(); -ListUserReviewsData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.listUserReviews().ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### GetMovieById -#### Required Arguments -```dart -String id = ...; -ExampleConnector.instance.getMovieById( - id: id, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.getMovieById( - id: id, -); -GetMovieByIdData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String id = ...; - -final ref = ExampleConnector.instance.getMovieById( - id: id, -).ref(); -ref.execute(); - -ref.subscribe(...); -``` - - -### SearchMovie -#### Required Arguments -```dart -// No required arguments -ExampleConnector.instance.searchMovie().execute(); -``` - -#### Optional Arguments -We return a builder for each query. For SearchMovie, we created `SearchMovieBuilder`. For queries and mutations with optional parameters, we return a builder class. -The builder pattern allows Data Connect to distinguish between fields that haven't been set and fields that have been set to null. A field can be set by calling its respective setter method like below: -```dart -class SearchMovieVariablesBuilder { - ... - - SearchMovieVariablesBuilder titleInput(String? t) { - _titleInput.value = t; - return this; - } - SearchMovieVariablesBuilder genre(String? t) { - _genre.value = t; - return this; - } - - ... -} -ExampleConnector.instance.searchMovie() -.titleInput(titleInput) -.genre(genre) -.execute(); -``` - -#### Return Type -`execute()` returns a `QueryResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -/// Result of a query request. Created to hold extra variables in the future. -class QueryResult extends OperationResult { - QueryResult(super.dataConnect, super.data, super.ref); -} - -final result = await ExampleConnector.instance.searchMovie(); -SearchMovieData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -final ref = ExampleConnector.instance.searchMovie().ref(); -ref.execute(); - -ref.subscribe(...); -``` - -## Mutations - -### CreateMovie -#### Required Arguments -```dart -String title = ...; -String genre = ...; -String imageUrl = ...; -ExampleConnector.instance.createMovie( - title: title, - genre: genre, - imageUrl: imageUrl, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.createMovie( - title: title, - genre: genre, - imageUrl: imageUrl, -); -CreateMovieData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String title = ...; -String genre = ...; -String imageUrl = ...; - -final ref = ExampleConnector.instance.createMovie( - title: title, - genre: genre, - imageUrl: imageUrl, -).ref(); -ref.execute(); -``` - - -### UpsertUser -#### Required Arguments -```dart -String username = ...; -ExampleConnector.instance.upsertUser( - username: username, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.upsertUser( - username: username, -); -UpsertUserData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String username = ...; - -final ref = ExampleConnector.instance.upsertUser( - username: username, -).ref(); -ref.execute(); -``` - - -### AddReview -#### Required Arguments -```dart -String movieId = ...; -int rating = ...; -String reviewText = ...; -ExampleConnector.instance.addReview( - movieId: movieId, - rating: rating, - reviewText: reviewText, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.addReview( - movieId: movieId, - rating: rating, - reviewText: reviewText, -); -AddReviewData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String movieId = ...; -int rating = ...; -String reviewText = ...; - -final ref = ExampleConnector.instance.addReview( - movieId: movieId, - rating: rating, - reviewText: reviewText, -).ref(); -ref.execute(); -``` - - -### DeleteReview -#### Required Arguments -```dart -String movieId = ...; -ExampleConnector.instance.deleteReview( - movieId: movieId, -).execute(); -``` - - - -#### Return Type -`execute()` returns a `OperationResult` -```dart -/// Result of an Operation Request (query/mutation). -class OperationResult { - OperationResult(this.dataConnect, this.data, this.ref); - Data data; - OperationRef ref; - FirebaseDataConnect dataConnect; -} - -final result = await ExampleConnector.instance.deleteReview( - movieId: movieId, -); -DeleteReviewData data = result.data; -final ref = result.ref; -``` - -#### Getting the Ref -Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation. -An example of how to use the `Ref` object is shown below: -```dart -String movieId = ...; - -final ref = ExampleConnector.instance.deleteReview( - movieId: movieId, -).ref(); -ref.execute(); -``` - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/add_review.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/add_review.dart deleted file mode 100644 index fc78c415..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/add_review.dart +++ /dev/null @@ -1,139 +0,0 @@ -part of 'generated.dart'; - -class AddReviewVariablesBuilder { - String movieId; - int rating; - String reviewText; - - final FirebaseDataConnect _dataConnect; - AddReviewVariablesBuilder(this._dataConnect, {required this.movieId,required this.rating,required this.reviewText,}); - Deserializer dataDeserializer = (dynamic json) => AddReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (AddReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - AddReviewVariables vars= AddReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,); - return _dataConnect.mutation("AddReview", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class AddReviewReviewUpsert { - final String userId; - final String movieId; - AddReviewReviewUpsert.fromJson(dynamic json): - - userId = nativeFromJson(json['userId']), - movieId = nativeFromJson(json['movieId']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final AddReviewReviewUpsert otherTyped = other as AddReviewReviewUpsert; - return userId == otherTyped.userId && - movieId == otherTyped.movieId; - - } - @override - int get hashCode => Object.hashAll([userId.hashCode, movieId.hashCode]); - - - Map toJson() { - Map json = {}; - json['userId'] = nativeToJson(userId); - json['movieId'] = nativeToJson(movieId); - return json; - } - - AddReviewReviewUpsert({ - required this.userId, - required this.movieId, - }); -} - -@immutable -class AddReviewData { - final AddReviewReviewUpsert review_upsert; - AddReviewData.fromJson(dynamic json): - - review_upsert = AddReviewReviewUpsert.fromJson(json['review_upsert']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final AddReviewData otherTyped = other as AddReviewData; - return review_upsert == otherTyped.review_upsert; - - } - @override - int get hashCode => review_upsert.hashCode; - - - Map toJson() { - Map json = {}; - json['review_upsert'] = review_upsert.toJson(); - return json; - } - - AddReviewData({ - required this.review_upsert, - }); -} - -@immutable -class AddReviewVariables { - final String movieId; - final int rating; - final String reviewText; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - AddReviewVariables.fromJson(Map json): - - movieId = nativeFromJson(json['movieId']), - rating = nativeFromJson(json['rating']), - reviewText = nativeFromJson(json['reviewText']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final AddReviewVariables otherTyped = other as AddReviewVariables; - return movieId == otherTyped.movieId && - rating == otherTyped.rating && - reviewText == otherTyped.reviewText; - - } - @override - int get hashCode => Object.hashAll([movieId.hashCode, rating.hashCode, reviewText.hashCode]); - - - Map toJson() { - Map json = {}; - json['movieId'] = nativeToJson(movieId); - json['rating'] = nativeToJson(rating); - json['reviewText'] = nativeToJson(reviewText); - return json; - } - - AddReviewVariables({ - required this.movieId, - required this.rating, - required this.reviewText, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/create_movie.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/create_movie.dart deleted file mode 100644 index abdd637c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/create_movie.dart +++ /dev/null @@ -1,134 +0,0 @@ -part of 'generated.dart'; - -class CreateMovieVariablesBuilder { - String title; - String genre; - String imageUrl; - - final FirebaseDataConnect _dataConnect; - CreateMovieVariablesBuilder(this._dataConnect, {required this.title,required this.genre,required this.imageUrl,}); - Deserializer dataDeserializer = (dynamic json) => CreateMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (CreateMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - CreateMovieVariables vars= CreateMovieVariables(title: title,genre: genre,imageUrl: imageUrl,); - return _dataConnect.mutation("CreateMovie", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class CreateMovieMovieInsert { - final String id; - CreateMovieMovieInsert.fromJson(dynamic json): - - id = nativeFromJson(json['id']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final CreateMovieMovieInsert otherTyped = other as CreateMovieMovieInsert; - return id == otherTyped.id; - - } - @override - int get hashCode => id.hashCode; - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - return json; - } - - CreateMovieMovieInsert({ - required this.id, - }); -} - -@immutable -class CreateMovieData { - final CreateMovieMovieInsert movie_insert; - CreateMovieData.fromJson(dynamic json): - - movie_insert = CreateMovieMovieInsert.fromJson(json['movie_insert']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final CreateMovieData otherTyped = other as CreateMovieData; - return movie_insert == otherTyped.movie_insert; - - } - @override - int get hashCode => movie_insert.hashCode; - - - Map toJson() { - Map json = {}; - json['movie_insert'] = movie_insert.toJson(); - return json; - } - - CreateMovieData({ - required this.movie_insert, - }); -} - -@immutable -class CreateMovieVariables { - final String title; - final String genre; - final String imageUrl; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - CreateMovieVariables.fromJson(Map json): - - title = nativeFromJson(json['title']), - genre = nativeFromJson(json['genre']), - imageUrl = nativeFromJson(json['imageUrl']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final CreateMovieVariables otherTyped = other as CreateMovieVariables; - return title == otherTyped.title && - genre == otherTyped.genre && - imageUrl == otherTyped.imageUrl; - - } - @override - int get hashCode => Object.hashAll([title.hashCode, genre.hashCode, imageUrl.hashCode]); - - - Map toJson() { - Map json = {}; - json['title'] = nativeToJson(title); - json['genre'] = nativeToJson(genre); - json['imageUrl'] = nativeToJson(imageUrl); - return json; - } - - CreateMovieVariables({ - required this.title, - required this.genre, - required this.imageUrl, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/delete_review.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/delete_review.dart deleted file mode 100644 index e62dd741..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/delete_review.dart +++ /dev/null @@ -1,129 +0,0 @@ -part of 'generated.dart'; - -class DeleteReviewVariablesBuilder { - String movieId; - - final FirebaseDataConnect _dataConnect; - DeleteReviewVariablesBuilder(this._dataConnect, {required this.movieId,}); - Deserializer dataDeserializer = (dynamic json) => DeleteReviewData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (DeleteReviewVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - DeleteReviewVariables vars= DeleteReviewVariables(movieId: movieId,); - return _dataConnect.mutation("DeleteReview", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class DeleteReviewReviewDelete { - final String userId; - final String movieId; - DeleteReviewReviewDelete.fromJson(dynamic json): - - userId = nativeFromJson(json['userId']), - movieId = nativeFromJson(json['movieId']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final DeleteReviewReviewDelete otherTyped = other as DeleteReviewReviewDelete; - return userId == otherTyped.userId && - movieId == otherTyped.movieId; - - } - @override - int get hashCode => Object.hashAll([userId.hashCode, movieId.hashCode]); - - - Map toJson() { - Map json = {}; - json['userId'] = nativeToJson(userId); - json['movieId'] = nativeToJson(movieId); - return json; - } - - DeleteReviewReviewDelete({ - required this.userId, - required this.movieId, - }); -} - -@immutable -class DeleteReviewData { - final DeleteReviewReviewDelete? review_delete; - DeleteReviewData.fromJson(dynamic json): - - review_delete = json['review_delete'] == null ? null : DeleteReviewReviewDelete.fromJson(json['review_delete']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final DeleteReviewData otherTyped = other as DeleteReviewData; - return review_delete == otherTyped.review_delete; - - } - @override - int get hashCode => review_delete.hashCode; - - - Map toJson() { - Map json = {}; - if (review_delete != null) { - json['review_delete'] = review_delete!.toJson(); - } - return json; - } - - DeleteReviewData({ - this.review_delete, - }); -} - -@immutable -class DeleteReviewVariables { - final String movieId; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - DeleteReviewVariables.fromJson(Map json): - - movieId = nativeFromJson(json['movieId']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final DeleteReviewVariables otherTyped = other as DeleteReviewVariables; - return movieId == otherTyped.movieId; - - } - @override - int get hashCode => movieId.hashCode; - - - Map toJson() { - Map json = {}; - json['movieId'] = nativeToJson(movieId); - return json; - } - - DeleteReviewVariables({ - required this.movieId, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/generated.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/generated.dart deleted file mode 100644 index 580adbb3..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/generated.dart +++ /dev/null @@ -1,93 +0,0 @@ -library dataconnect_generated; -import 'package:firebase_data_connect/firebase_data_connect.dart'; -import 'package:flutter/foundation.dart'; -import 'dart:convert'; - -part 'create_movie.dart'; - -part 'upsert_user.dart'; - -part 'add_review.dart'; - -part 'delete_review.dart'; - -part 'list_movies.dart'; - -part 'list_users.dart'; - -part 'list_user_reviews.dart'; - -part 'get_movie_by_id.dart'; - -part 'search_movie.dart'; - - - - - - - -class ExampleConnector { - - - CreateMovieVariablesBuilder createMovie ({required String title, required String genre, required String imageUrl, }) { - return CreateMovieVariablesBuilder(dataConnect, title: title,genre: genre,imageUrl: imageUrl,); - } - - - UpsertUserVariablesBuilder upsertUser ({required String username, }) { - return UpsertUserVariablesBuilder(dataConnect, username: username,); - } - - - AddReviewVariablesBuilder addReview ({required String movieId, required int rating, required String reviewText, }) { - return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,); - } - - - DeleteReviewVariablesBuilder deleteReview ({required String movieId, }) { - return DeleteReviewVariablesBuilder(dataConnect, movieId: movieId,); - } - - - ListMoviesVariablesBuilder listMovies () { - return ListMoviesVariablesBuilder(dataConnect, ); - } - - - ListUsersVariablesBuilder listUsers () { - return ListUsersVariablesBuilder(dataConnect, ); - } - - - ListUserReviewsVariablesBuilder listUserReviews () { - return ListUserReviewsVariablesBuilder(dataConnect, ); - } - - - GetMovieByIdVariablesBuilder getMovieById ({required String id, }) { - return GetMovieByIdVariablesBuilder(dataConnect, id: id,); - } - - - SearchMovieVariablesBuilder searchMovie () { - return SearchMovieVariablesBuilder(dataConnect, ); - } - - - static ConnectorConfig connectorConfig = ConnectorConfig( - 'us-central1', - 'example', - 'client-krow-poc', - ); - - ExampleConnector({required this.dataConnect}); - static ExampleConnector get instance { - return ExampleConnector( - dataConnect: FirebaseDataConnect.instanceFor( - connectorConfig: connectorConfig, - sdkType: CallerSDKType.generated)); - } - - FirebaseDataConnect dataConnect; -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/get_movie_by_id.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/get_movie_by_id.dart deleted file mode 100644 index 154704ac..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/get_movie_by_id.dart +++ /dev/null @@ -1,297 +0,0 @@ -part of 'generated.dart'; - -class GetMovieByIdVariablesBuilder { - String id; - - final FirebaseDataConnect _dataConnect; - GetMovieByIdVariablesBuilder(this._dataConnect, {required this.id,}); - Deserializer dataDeserializer = (dynamic json) => GetMovieByIdData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (GetMovieByIdVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - GetMovieByIdVariables vars= GetMovieByIdVariables(id: id,); - return _dataConnect.query("GetMovieById", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class GetMovieByIdMovie { - final String id; - final String title; - final String imageUrl; - final String? genre; - final GetMovieByIdMovieMetadata? metadata; - final List reviews; - GetMovieByIdMovie.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']), - imageUrl = nativeFromJson(json['imageUrl']), - genre = json['genre'] == null ? null : nativeFromJson(json['genre']), - metadata = json['metadata'] == null ? null : GetMovieByIdMovieMetadata.fromJson(json['metadata']), - reviews = (json['reviews'] as List) - .map((e) => GetMovieByIdMovieReviews.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovie otherTyped = other as GetMovieByIdMovie; - return id == otherTyped.id && - title == otherTyped.title && - imageUrl == otherTyped.imageUrl && - genre == otherTyped.genre && - metadata == otherTyped.metadata && - reviews == otherTyped.reviews; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode, imageUrl.hashCode, genre.hashCode, metadata.hashCode, reviews.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - json['imageUrl'] = nativeToJson(imageUrl); - if (genre != null) { - json['genre'] = nativeToJson(genre); - } - if (metadata != null) { - json['metadata'] = metadata!.toJson(); - } - json['reviews'] = reviews.map((e) => e.toJson()).toList(); - return json; - } - - GetMovieByIdMovie({ - required this.id, - required this.title, - required this.imageUrl, - this.genre, - this.metadata, - required this.reviews, - }); -} - -@immutable -class GetMovieByIdMovieMetadata { - final double? rating; - final int? releaseYear; - final String? description; - GetMovieByIdMovieMetadata.fromJson(dynamic json): - - rating = json['rating'] == null ? null : nativeFromJson(json['rating']), - releaseYear = json['releaseYear'] == null ? null : nativeFromJson(json['releaseYear']), - description = json['description'] == null ? null : nativeFromJson(json['description']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovieMetadata otherTyped = other as GetMovieByIdMovieMetadata; - return rating == otherTyped.rating && - releaseYear == otherTyped.releaseYear && - description == otherTyped.description; - - } - @override - int get hashCode => Object.hashAll([rating.hashCode, releaseYear.hashCode, description.hashCode]); - - - Map toJson() { - Map json = {}; - if (rating != null) { - json['rating'] = nativeToJson(rating); - } - if (releaseYear != null) { - json['releaseYear'] = nativeToJson(releaseYear); - } - if (description != null) { - json['description'] = nativeToJson(description); - } - return json; - } - - GetMovieByIdMovieMetadata({ - this.rating, - this.releaseYear, - this.description, - }); -} - -@immutable -class GetMovieByIdMovieReviews { - final String? reviewText; - final DateTime reviewDate; - final int? rating; - final GetMovieByIdMovieReviewsUser user; - GetMovieByIdMovieReviews.fromJson(dynamic json): - - reviewText = json['reviewText'] == null ? null : nativeFromJson(json['reviewText']), - reviewDate = nativeFromJson(json['reviewDate']), - rating = json['rating'] == null ? null : nativeFromJson(json['rating']), - user = GetMovieByIdMovieReviewsUser.fromJson(json['user']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovieReviews otherTyped = other as GetMovieByIdMovieReviews; - return reviewText == otherTyped.reviewText && - reviewDate == otherTyped.reviewDate && - rating == otherTyped.rating && - user == otherTyped.user; - - } - @override - int get hashCode => Object.hashAll([reviewText.hashCode, reviewDate.hashCode, rating.hashCode, user.hashCode]); - - - Map toJson() { - Map json = {}; - if (reviewText != null) { - json['reviewText'] = nativeToJson(reviewText); - } - json['reviewDate'] = nativeToJson(reviewDate); - if (rating != null) { - json['rating'] = nativeToJson(rating); - } - json['user'] = user.toJson(); - return json; - } - - GetMovieByIdMovieReviews({ - this.reviewText, - required this.reviewDate, - this.rating, - required this.user, - }); -} - -@immutable -class GetMovieByIdMovieReviewsUser { - final String id; - final String username; - GetMovieByIdMovieReviewsUser.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - username = nativeFromJson(json['username']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdMovieReviewsUser otherTyped = other as GetMovieByIdMovieReviewsUser; - return id == otherTyped.id && - username == otherTyped.username; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, username.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['username'] = nativeToJson(username); - return json; - } - - GetMovieByIdMovieReviewsUser({ - required this.id, - required this.username, - }); -} - -@immutable -class GetMovieByIdData { - final GetMovieByIdMovie? movie; - GetMovieByIdData.fromJson(dynamic json): - - movie = json['movie'] == null ? null : GetMovieByIdMovie.fromJson(json['movie']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdData otherTyped = other as GetMovieByIdData; - return movie == otherTyped.movie; - - } - @override - int get hashCode => movie.hashCode; - - - Map toJson() { - Map json = {}; - if (movie != null) { - json['movie'] = movie!.toJson(); - } - return json; - } - - GetMovieByIdData({ - this.movie, - }); -} - -@immutable -class GetMovieByIdVariables { - final String id; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - GetMovieByIdVariables.fromJson(Map json): - - id = nativeFromJson(json['id']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final GetMovieByIdVariables otherTyped = other as GetMovieByIdVariables; - return id == otherTyped.id; - - } - @override - int get hashCode => id.hashCode; - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - return json; - } - - GetMovieByIdVariables({ - required this.id, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_movies.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_movies.dart deleted file mode 100644 index 4a67d768..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_movies.dart +++ /dev/null @@ -1,105 +0,0 @@ -part of 'generated.dart'; - -class ListMoviesVariablesBuilder { - - final FirebaseDataConnect _dataConnect; - ListMoviesVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json)); - - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - - return _dataConnect.query("ListMovies", dataDeserializer, emptySerializer, null); - } -} - -@immutable -class ListMoviesMovies { - final String id; - final String title; - final String imageUrl; - final String? genre; - ListMoviesMovies.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']), - imageUrl = nativeFromJson(json['imageUrl']), - genre = json['genre'] == null ? null : nativeFromJson(json['genre']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListMoviesMovies otherTyped = other as ListMoviesMovies; - return id == otherTyped.id && - title == otherTyped.title && - imageUrl == otherTyped.imageUrl && - genre == otherTyped.genre; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode, imageUrl.hashCode, genre.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - json['imageUrl'] = nativeToJson(imageUrl); - if (genre != null) { - json['genre'] = nativeToJson(genre); - } - return json; - } - - ListMoviesMovies({ - required this.id, - required this.title, - required this.imageUrl, - this.genre, - }); -} - -@immutable -class ListMoviesData { - final List movies; - ListMoviesData.fromJson(dynamic json): - - movies = (json['movies'] as List) - .map((e) => ListMoviesMovies.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListMoviesData otherTyped = other as ListMoviesData; - return movies == otherTyped.movies; - - } - @override - int get hashCode => movies.hashCode; - - - Map toJson() { - Map json = {}; - json['movies'] = movies.map((e) => e.toJson()).toList(); - return json; - } - - ListMoviesData({ - required this.movies, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_user_reviews.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_user_reviews.dart deleted file mode 100644 index d6053f58..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_user_reviews.dart +++ /dev/null @@ -1,192 +0,0 @@ -part of 'generated.dart'; - -class ListUserReviewsVariablesBuilder { - - final FirebaseDataConnect _dataConnect; - ListUserReviewsVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListUserReviewsData.fromJson(jsonDecode(json)); - - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - - return _dataConnect.query("ListUserReviews", dataDeserializer, emptySerializer, null); - } -} - -@immutable -class ListUserReviewsUser { - final String id; - final String username; - final List reviews; - ListUserReviewsUser.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - username = nativeFromJson(json['username']), - reviews = (json['reviews'] as List) - .map((e) => ListUserReviewsUserReviews.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsUser otherTyped = other as ListUserReviewsUser; - return id == otherTyped.id && - username == otherTyped.username && - reviews == otherTyped.reviews; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, username.hashCode, reviews.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['username'] = nativeToJson(username); - json['reviews'] = reviews.map((e) => e.toJson()).toList(); - return json; - } - - ListUserReviewsUser({ - required this.id, - required this.username, - required this.reviews, - }); -} - -@immutable -class ListUserReviewsUserReviews { - final int? rating; - final DateTime reviewDate; - final String? reviewText; - final ListUserReviewsUserReviewsMovie movie; - ListUserReviewsUserReviews.fromJson(dynamic json): - - rating = json['rating'] == null ? null : nativeFromJson(json['rating']), - reviewDate = nativeFromJson(json['reviewDate']), - reviewText = json['reviewText'] == null ? null : nativeFromJson(json['reviewText']), - movie = ListUserReviewsUserReviewsMovie.fromJson(json['movie']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsUserReviews otherTyped = other as ListUserReviewsUserReviews; - return rating == otherTyped.rating && - reviewDate == otherTyped.reviewDate && - reviewText == otherTyped.reviewText && - movie == otherTyped.movie; - - } - @override - int get hashCode => Object.hashAll([rating.hashCode, reviewDate.hashCode, reviewText.hashCode, movie.hashCode]); - - - Map toJson() { - Map json = {}; - if (rating != null) { - json['rating'] = nativeToJson(rating); - } - json['reviewDate'] = nativeToJson(reviewDate); - if (reviewText != null) { - json['reviewText'] = nativeToJson(reviewText); - } - json['movie'] = movie.toJson(); - return json; - } - - ListUserReviewsUserReviews({ - this.rating, - required this.reviewDate, - this.reviewText, - required this.movie, - }); -} - -@immutable -class ListUserReviewsUserReviewsMovie { - final String id; - final String title; - ListUserReviewsUserReviewsMovie.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsUserReviewsMovie otherTyped = other as ListUserReviewsUserReviewsMovie; - return id == otherTyped.id && - title == otherTyped.title; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - return json; - } - - ListUserReviewsUserReviewsMovie({ - required this.id, - required this.title, - }); -} - -@immutable -class ListUserReviewsData { - final ListUserReviewsUser? user; - ListUserReviewsData.fromJson(dynamic json): - - user = json['user'] == null ? null : ListUserReviewsUser.fromJson(json['user']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUserReviewsData otherTyped = other as ListUserReviewsData; - return user == otherTyped.user; - - } - @override - int get hashCode => user.hashCode; - - - Map toJson() { - Map json = {}; - if (user != null) { - json['user'] = user!.toJson(); - } - return json; - } - - ListUserReviewsData({ - this.user, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_users.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_users.dart deleted file mode 100644 index 5fead7eb..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/list_users.dart +++ /dev/null @@ -1,93 +0,0 @@ -part of 'generated.dart'; - -class ListUsersVariablesBuilder { - - final FirebaseDataConnect _dataConnect; - ListUsersVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => ListUsersData.fromJson(jsonDecode(json)); - - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - - return _dataConnect.query("ListUsers", dataDeserializer, emptySerializer, null); - } -} - -@immutable -class ListUsersUsers { - final String id; - final String username; - ListUsersUsers.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - username = nativeFromJson(json['username']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUsersUsers otherTyped = other as ListUsersUsers; - return id == otherTyped.id && - username == otherTyped.username; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, username.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['username'] = nativeToJson(username); - return json; - } - - ListUsersUsers({ - required this.id, - required this.username, - }); -} - -@immutable -class ListUsersData { - final List users; - ListUsersData.fromJson(dynamic json): - - users = (json['users'] as List) - .map((e) => ListUsersUsers.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final ListUsersData otherTyped = other as ListUsersData; - return users == otherTyped.users; - - } - @override - int get hashCode => users.hashCode; - - - Map toJson() { - Map json = {}; - json['users'] = users.map((e) => e.toJson()).toList(); - return json; - } - - ListUsersData({ - required this.users, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/search_movie.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/search_movie.dart deleted file mode 100644 index 19e5f2d7..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/search_movie.dart +++ /dev/null @@ -1,167 +0,0 @@ -part of 'generated.dart'; - -class SearchMovieVariablesBuilder { - Optional _titleInput = Optional.optional(nativeFromJson, nativeToJson); - Optional _genre = Optional.optional(nativeFromJson, nativeToJson); - - final FirebaseDataConnect _dataConnect; - SearchMovieVariablesBuilder titleInput(String? t) { - _titleInput.value = t; - return this; - } - SearchMovieVariablesBuilder genre(String? t) { - _genre.value = t; - return this; - } - - SearchMovieVariablesBuilder(this._dataConnect, ); - Deserializer dataDeserializer = (dynamic json) => SearchMovieData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (SearchMovieVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - QueryRef ref() { - SearchMovieVariables vars= SearchMovieVariables(titleInput: _titleInput,genre: _genre,); - return _dataConnect.query("SearchMovie", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class SearchMovieMovies { - final String id; - final String title; - final String? genre; - final String imageUrl; - SearchMovieMovies.fromJson(dynamic json): - - id = nativeFromJson(json['id']), - title = nativeFromJson(json['title']), - genre = json['genre'] == null ? null : nativeFromJson(json['genre']), - imageUrl = nativeFromJson(json['imageUrl']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final SearchMovieMovies otherTyped = other as SearchMovieMovies; - return id == otherTyped.id && - title == otherTyped.title && - genre == otherTyped.genre && - imageUrl == otherTyped.imageUrl; - - } - @override - int get hashCode => Object.hashAll([id.hashCode, title.hashCode, genre.hashCode, imageUrl.hashCode]); - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - json['title'] = nativeToJson(title); - if (genre != null) { - json['genre'] = nativeToJson(genre); - } - json['imageUrl'] = nativeToJson(imageUrl); - return json; - } - - SearchMovieMovies({ - required this.id, - required this.title, - this.genre, - required this.imageUrl, - }); -} - -@immutable -class SearchMovieData { - final List movies; - SearchMovieData.fromJson(dynamic json): - - movies = (json['movies'] as List) - .map((e) => SearchMovieMovies.fromJson(e)) - .toList(); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final SearchMovieData otherTyped = other as SearchMovieData; - return movies == otherTyped.movies; - - } - @override - int get hashCode => movies.hashCode; - - - Map toJson() { - Map json = {}; - json['movies'] = movies.map((e) => e.toJson()).toList(); - return json; - } - - SearchMovieData({ - required this.movies, - }); -} - -@immutable -class SearchMovieVariables { - late final OptionaltitleInput; - late final Optionalgenre; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - SearchMovieVariables.fromJson(Map json) { - - - titleInput = Optional.optional(nativeFromJson, nativeToJson); - titleInput.value = json['titleInput'] == null ? null : nativeFromJson(json['titleInput']); - - - genre = Optional.optional(nativeFromJson, nativeToJson); - genre.value = json['genre'] == null ? null : nativeFromJson(json['genre']); - - } - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final SearchMovieVariables otherTyped = other as SearchMovieVariables; - return titleInput == otherTyped.titleInput && - genre == otherTyped.genre; - - } - @override - int get hashCode => Object.hashAll([titleInput.hashCode, genre.hashCode]); - - - Map toJson() { - Map json = {}; - if(titleInput.state == OptionalState.set) { - json['titleInput'] = titleInput.toJson(); - } - if(genre.state == OptionalState.set) { - json['genre'] = genre.toJson(); - } - return json; - } - - SearchMovieVariables({ - required this.titleInput, - required this.genre, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/upsert_user.dart b/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/upsert_user.dart deleted file mode 100644 index f797b726..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/dataconnect_generated/upsert_user.dart +++ /dev/null @@ -1,122 +0,0 @@ -part of 'generated.dart'; - -class UpsertUserVariablesBuilder { - String username; - - final FirebaseDataConnect _dataConnect; - UpsertUserVariablesBuilder(this._dataConnect, {required this.username,}); - Deserializer dataDeserializer = (dynamic json) => UpsertUserData.fromJson(jsonDecode(json)); - Serializer varsSerializer = (UpsertUserVariables vars) => jsonEncode(vars.toJson()); - Future> execute() { - return ref().execute(); - } - - MutationRef ref() { - UpsertUserVariables vars= UpsertUserVariables(username: username,); - return _dataConnect.mutation("UpsertUser", dataDeserializer, varsSerializer, vars); - } -} - -@immutable -class UpsertUserUserUpsert { - final String id; - UpsertUserUserUpsert.fromJson(dynamic json): - - id = nativeFromJson(json['id']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final UpsertUserUserUpsert otherTyped = other as UpsertUserUserUpsert; - return id == otherTyped.id; - - } - @override - int get hashCode => id.hashCode; - - - Map toJson() { - Map json = {}; - json['id'] = nativeToJson(id); - return json; - } - - UpsertUserUserUpsert({ - required this.id, - }); -} - -@immutable -class UpsertUserData { - final UpsertUserUserUpsert user_upsert; - UpsertUserData.fromJson(dynamic json): - - user_upsert = UpsertUserUserUpsert.fromJson(json['user_upsert']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final UpsertUserData otherTyped = other as UpsertUserData; - return user_upsert == otherTyped.user_upsert; - - } - @override - int get hashCode => user_upsert.hashCode; - - - Map toJson() { - Map json = {}; - json['user_upsert'] = user_upsert.toJson(); - return json; - } - - UpsertUserData({ - required this.user_upsert, - }); -} - -@immutable -class UpsertUserVariables { - final String username; - @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.') - UpsertUserVariables.fromJson(Map json): - - username = nativeFromJson(json['username']); - @override - bool operator ==(Object other) { - if(identical(this, other)) { - return true; - } - if(other.runtimeType != runtimeType) { - return false; - } - - final UpsertUserVariables otherTyped = other as UpsertUserVariables; - return username == otherTyped.username; - - } - @override - int get hashCode => username.hashCode; - - - Map toJson() { - Map json = {}; - json['username'] = nativeToJson(username); - return json; - } - - UpsertUserVariables({ - required this.username, - }); -} - diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/main.dart b/apps/mobile/prototypes/staff_mobile_application/lib/main.dart deleted file mode 100644 index b62f5adf..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/main.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; -import 'theme.dart'; -import 'router.dart'; -import 'widgets/web_mobile_frame.dart'; - -void main() async { - WidgetsFlutterBinding.ensureInitialized(); - //await Firebase.initializeApp(); - - const app = AppRoot(); - - runApp(ProviderScope(child: kIsWeb ? const WebMobileFrame(child: app) : app)); -} - -class AppRoot extends ConsumerWidget { - const AppRoot({super.key}); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return MaterialApp.router( - title: 'Krow Staff App', - theme: AppTheme.lightTheme, - routerConfig: router, - debugShowCheckedModeBanner: false, - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/models/shift.dart b/apps/mobile/prototypes/staff_mobile_application/lib/models/shift.dart deleted file mode 100644 index d1864145..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/models/shift.dart +++ /dev/null @@ -1,59 +0,0 @@ -class Shift { - final String id; - final String title; - final String clientName; - final String? logoUrl; - final double hourlyRate; - final String location; - final String locationAddress; - final String date; - final String startTime; - final String endTime; - final String createdDate; - final bool? tipsAvailable; - final bool? travelTime; - final bool? mealProvided; - final bool? parkingAvailable; - final bool? gasCompensation; - final String? description; - final String? instructions; - final List? managers; - final double? latitude; - final double? longitude; - final String? status; - final int? durationDays; // For multi-day shifts - - Shift({ - required this.id, - required this.title, - required this.clientName, - this.logoUrl, - required this.hourlyRate, - required this.location, - required this.locationAddress, - required this.date, - required this.startTime, - required this.endTime, - required this.createdDate, - this.tipsAvailable, - this.travelTime, - this.mealProvided, - this.parkingAvailable, - this.gasCompensation, - this.description, - this.instructions, - this.managers, - this.latitude, - this.longitude, - this.status, - this.durationDays, - }); -} - -class ShiftManager { - final String name; - final String phone; - final String? avatar; - - ShiftManager({required this.name, required this.phone, this.avatar}); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/router.dart b/apps/mobile/prototypes/staff_mobile_application/lib/router.dart deleted file mode 100644 index e6287855..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/router.dart +++ /dev/null @@ -1,198 +0,0 @@ -import 'package:go_router/go_router.dart'; -import 'screens/auth/get_started_screen.dart'; -import 'screens/auth/phone_verification_screen.dart'; -import 'screens/auth/profile_setup_screen.dart'; -import 'screens/worker/worker_home_screen.dart'; -import 'screens/worker/shifts_screen.dart'; -import 'screens/worker/payments_screen.dart'; -import 'screens/worker/clock_in_screen.dart'; -import 'screens/worker/benefits_screen.dart'; -import 'screens/worker/availability_screen.dart'; -import 'screens/worker/earnings_screen.dart'; -import 'screens/worker/early_pay_screen.dart'; -import 'screens/worker/jobs_screen.dart'; -import 'screens/worker/worker_profile_screen.dart'; -import 'screens/worker/worker_profile/support/faqs_screen.dart'; -import 'screens/worker/worker_profile/support/privacy_screen.dart'; -import 'screens/worker/worker_profile/support/messages_screen.dart'; -import 'screens/worker/worker_profile/level_up/krow_university_screen.dart'; -import 'screens/worker/worker_profile/level_up/trainings_screen.dart'; -import 'screens/worker/worker_profile/level_up/leaderboard_screen.dart'; -import 'screens/worker/worker_profile/finances/bank_account_screen.dart'; -import 'screens/worker/worker_profile/finances/time_card_screen.dart'; -import 'screens/worker/worker_profile/compliance/documents_screen.dart'; -import 'screens/worker/worker_profile/compliance/certificates_screen.dart'; -import 'screens/worker/worker_profile/compliance/tax_forms_screen.dart'; -import 'screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart'; -import 'screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart'; -import 'screens/worker/worker_profile/onboarding/personal_info_screen.dart'; -import 'screens/worker/worker_profile/onboarding/emergency_contact_screen.dart'; -import 'screens/worker/worker_profile/onboarding/experience_screen.dart'; -import 'screens/worker/worker_profile/onboarding/attire_screen.dart'; -import 'screens/worker/shift_details_screen.dart'; -import 'widgets/scaffold_with_nav_bar.dart'; - -final router = GoRouter( - initialLocation: '/get-started', - routes: [ - GoRoute( - path: '/get-started', - builder: (context, state) => const GetStartedScreen(), - ), - GoRoute( - path: '/phone-verification', - builder: (context, state) { - final mode = state.uri.queryParameters['mode'] ?? 'signup'; - return PhoneVerificationScreen(mode: mode); - }, - ), - GoRoute( - path: '/profile-setup', - builder: (context, state) => const ProfileSetupScreen(), - ), - GoRoute( - path: '/benefits', - builder: (context, state) => const BenefitsScreen(), - ), - GoRoute( - path: '/availability', - builder: (context, state) => const AvailabilityScreen(), - ), - GoRoute( - path: '/earnings', - builder: (context, state) => const EarningsScreen(), - ), - GoRoute( - path: '/early-pay', - builder: (context, state) => const EarlyPayScreen(), - ), - GoRoute(path: '/jobs', builder: (context, state) => const JobsScreen()), - GoRoute(path: '/faqs', builder: (context, state) => const FAQsScreen()), - GoRoute( - path: '/privacy', - builder: (context, state) => const PrivacyScreen(), - ), - GoRoute( - path: '/messages', - builder: (context, state) => const MessagesScreen(), - ), - GoRoute( - path: '/krow-university', - builder: (context, state) => const KrowUniversityScreen(), - ), - GoRoute( - path: '/trainings', - builder: (context, state) => const TrainingsScreen(), - ), - GoRoute( - path: '/leaderboard', - builder: (context, state) => const LeaderboardScreen(), - ), - GoRoute( - path: '/bank-account', - builder: (context, state) => const BankAccountScreen(), - ), - GoRoute( - path: '/time-card', - builder: (context, state) => const TimeCardScreen(), - ), - GoRoute( - path: '/documents', - builder: (context, state) => const DocumentsScreen(), - ), - GoRoute( - path: '/certificates', - builder: (context, state) => const CertificatesScreen(), - ), - GoRoute( - path: '/tax-forms', - builder: (context, state) => const TaxFormsScreen(), - ), - GoRoute( - path: '/taxforms/i9', - builder: (context, state) => const FormI9Screen(), - ), - GoRoute( - path: '/taxforms/w4', - builder: (context, state) => const FormW4Screen(), - ), - GoRoute( - path: '/personal-info', - builder: (context, state) => const PersonalInfoScreen(), - ), - GoRoute( - path: '/emergency-contact', - builder: (context, state) => const EmergencyContactScreen(), - ), - GoRoute( - path: '/experience', - builder: (context, state) => const ExperienceScreen(), - ), - GoRoute(path: '/attire', builder: (context, state) => const AttireScreen()), - GoRoute( - path: '/shift-details/:id', - builder: (context, state) { - final id = state.pathParameters['id']!; - final shift = - state.extra - as dynamic; // Cast to dynamic first to avoid type issues if import is missing in router - return ShiftDetailsScreen(shiftId: id, shift: shift); - }, - ), - StatefulShellRoute.indexedStack( - builder: (context, state, navigationShell) { - return ScaffoldWithNavBar(navigationShell: navigationShell); - }, - branches: [ - // Index 0: Shifts - StatefulShellBranch( - routes: [ - GoRoute( - path: '/shifts', - builder: (context, state) { - final tab = state.uri.queryParameters['tab']; - return ShiftsScreen(initialTab: tab); - }, - ), - ], - ), - // Index 1: Payments - StatefulShellBranch( - routes: [ - GoRoute( - path: '/payments', - builder: (context, state) => const PaymentsScreen(), - ), - ], - ), - // Index 2: Home - StatefulShellBranch( - routes: [ - GoRoute( - path: '/worker-home', - builder: (context, state) => const WorkerHomeScreen(), - ), - ], - ), - // Index 3: Clock In - StatefulShellBranch( - routes: [ - GoRoute( - path: '/clock-in', - builder: (context, state) => const ClockInScreen(), - ), - ], - ), - // Index 4: Profile - StatefulShellBranch( - routes: [ - GoRoute( - path: '/worker-profile', - builder: (context, state) => const WorkerProfileScreen(), - ), - ], - ), - ], - ), - ], -); diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/get_started_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/get_started_screen.dart deleted file mode 100644 index e6100c9d..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/get_started_screen.dart +++ /dev/null @@ -1,182 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; -import '../../theme.dart'; - -class GetStartedScreen extends StatelessWidget { - const GetStartedScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFF1A2234), - body: SafeArea( - child: Column( - children: [ - const SizedBox(height: 32), - // Logo - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - child: Image.network( - 'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png', - height: 40, - ), - ), - - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // Hero Image - Container( - width: 288, - height: 288, - margin: const EdgeInsets.only(bottom: 32), - decoration: BoxDecoration( - shape: BoxShape.circle, - color: const Color(0xFF3A4A5A).withOpacity(0.5), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ClipOval( - child: Image.network( - 'https://images.unsplash.com/photo-1577219491135-ce391730fb2c?w=400&h=400&fit=crop&crop=faces', - fit: BoxFit.cover, - ), - ), - ), - ), - - // Pagination dots - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 24, - height: 8, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(4), - ), - ), - const SizedBox(width: 8), - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.4), - borderRadius: BorderRadius.circular(4), - ), - ), - const SizedBox(width: 8), - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.4), - borderRadius: BorderRadius.circular(4), - ), - ), - ], - ), - - const SizedBox(height: 32), - - // Text content - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - child: Column( - children: [ - RichText( - textAlign: TextAlign.center, - text: TextSpan( - style: GoogleFonts.instrumentSans( - fontSize: 30, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - children: const [ - TextSpan(text: 'Work, Grow, '), - TextSpan( - text: 'Elevate', - style: TextStyle(color: AppColors.krowYellow), - ), - ], - ), - ), - const SizedBox(height: 16), - Text( - 'Build your career in hospitality with flexibility and freedom.', - textAlign: TextAlign.center, - style: GoogleFonts.instrumentSans( - fontSize: 16, - color: Colors.grey[400], - height: 1.5, - ), - ), - ], - ), - ), - ], - ), - ), - - // Bottom buttons - Padding( - padding: const EdgeInsets.fromLTRB(24, 0, 24, 40), - child: Column( - children: [ - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () { - // Navigate to PhoneVerification (Sign Up) - context.push('/phone-verification'); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowYellow, - foregroundColor: const Color(0xFF1A2234), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - textStyle: GoogleFonts.instrumentSans( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - child: const Text('Sign Up'), - ), - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - height: 56, - child: OutlinedButton( - onPressed: () { - // Navigate to PhoneVerification (Log In) - context.push('/phone-verification?mode=login'); - }, - style: OutlinedButton.styleFrom( - side: const BorderSide(color: Colors.grey, width: 2), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - textStyle: GoogleFonts.instrumentSans( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - child: const Text('Log In'), - ), - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/phone_verification_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/phone_verification_screen.dart deleted file mode 100644 index c52a279c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/phone_verification_screen.dart +++ /dev/null @@ -1,486 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class PhoneVerificationScreen extends StatefulWidget { - final String mode; - - const PhoneVerificationScreen({super.key, this.mode = 'signup'}); - - @override - State createState() => - _PhoneVerificationScreenState(); -} - -class _PhoneVerificationScreenState extends State { - String step = 'phone'; // phone, code - String phoneNumber = ''; - String countryCode = '+1'; - List code = ['', '', '', '', '', '']; - bool isLoading = false; - String error = ''; - int countdown = 0; - - final List _codeFocusNodes = List.generate( - 6, - (index) => FocusNode(), - ); - final List _codeControllers = List.generate( - 6, - (index) => TextEditingController(), - ); - - @override - void dispose() { - for (var node in _codeFocusNodes) { - node.dispose(); - } - for (var controller in _codeControllers) { - controller.dispose(); - } - super.dispose(); - } - - void _startTimer() { - if (countdown > 0) return; - setState(() { - countdown = 30; - }); - _tick(); - } - - void _tick() { - if (countdown > 0) { - Future.delayed(const Duration(seconds: 1), () { - if (mounted) { - setState(() { - countdown--; - }); - _tick(); - } - }); - } - } - - void _handleSendCode() async { - if (phoneNumber.length != 10) { - setState(() { - error = 'Please enter a valid 10-digit phone number'; - }); - return; - } - - setState(() { - isLoading = true; - error = ''; - }); - - await Future.delayed(const Duration(milliseconds: 1500)); - - if (mounted) { - setState(() { - isLoading = false; - step = 'code'; - }); - _startTimer(); - } - } - - void _handleVerifyCode() async { - String fullCode = code.join(''); - if (fullCode.length != 6) return; - - setState(() { - isLoading = true; - error = ''; - }); - - await Future.delayed(const Duration(milliseconds: 1500)); - - if (mounted) { - if (fullCode == '123456' || fullCode.length == 6) { - // Accept any 6 digit code for MVP - setState(() { - isLoading = false; - }); - if (widget.mode == 'login') { - context.go('/worker-home'); - } else { - context.go('/profile-setup'); - } - } else { - setState(() { - isLoading = false; - error = 'Invalid code. Please try again.'; - }); - } - } - } - - void _handleCodeChange(int index, String value) { - if (value.isNotEmpty && !RegExp(r'^\d*$').hasMatch(value)) return; - - setState(() { - code[index] = value; - error = ''; - }); - - if (value.isNotEmpty && index < 5) { - _codeFocusNodes[index + 1].requestFocus(); - } - - if (value.isNotEmpty && index == 5 && code.every((d) => d.isNotEmpty)) { - _handleVerifyCode(); - } - } - - void _handleResend() async { - if (countdown > 0) return; - setState(() { - isLoading = true; - }); - await Future.delayed(const Duration(seconds: 1)); - if (mounted) { - setState(() { - isLoading = false; - code = ['', '', '', '', '', '']; - for (var c in _codeControllers) c.clear(); - }); - _startTimer(); - } - } - - @override - Widget build(BuildContext context) { - // Specific colors for this screen - const Color bg = Color(0xFFF5F5F0); - const Color inputBg = Color(0xFFE8E8E0); - const Color textMain = Color(0xFF333F48); - const Color textSub = Color(0xFF666666); - - return Scaffold( - backgroundColor: bg, - appBar: AppBar( - backgroundColor: bg, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.arrowLeft, color: textMain), - onPressed: () { - if (step == 'code') { - setState(() { - step = 'phone'; - code = ['', '', '', '', '', '']; - for (var c in _codeControllers) c.clear(); - }); - } else { - context.pop(); - } - }, - ), - title: Text( - 'Phone Verification', - style: TextStyle( - color: textMain, - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - centerTitle: true, - ), - body: SafeArea( - child: Column( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0, - vertical: 32.0, - ), - child: step == 'phone' - ? _buildPhoneStep(textMain, textSub, inputBg) - : _buildCodeStep(textMain, textSub), - ), - ), - Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - children: [ - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: - (isLoading || - (step == 'phone' - ? phoneNumber.length != 10 - : code.any((d) => d.isEmpty))) - ? null - : (step == 'phone' - ? _handleSendCode - : _handleVerifyCode), - style: ElevatedButton.styleFrom( - backgroundColor: textMain, - foregroundColor: Colors.white, - disabledBackgroundColor: inputBg, - disabledForegroundColor: const Color(0xFF999999), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: isLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Colors.white, - ), - ) - : Text( - step == 'phone' ? 'Send Code' : 'Continue', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - ), - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Having trouble? ', - style: TextStyle(color: textSub, fontSize: 14), - ), - Text( - 'Contact Support', - style: TextStyle( - color: textMain, - fontWeight: FontWeight.w600, - fontSize: 14, - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildPhoneStep(Color textMain, Color textSub, Color inputBg) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Verify your phone number', - style: TextStyle( - color: textMain, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8), - Text( - 'We\'ll send you a verification code to get started.', - style: TextStyle(color: textSub, fontSize: 14), - ), - const SizedBox(height: 32), - Text('Phone Number', style: TextStyle(color: textSub, fontSize: 12)), - const SizedBox(height: 8), - Row( - children: [ - Container( - width: 100, - height: 48, - decoration: BoxDecoration( - color: inputBg, - borderRadius: BorderRadius.circular(8), - ), - alignment: Alignment.center, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('🇺🇸', style: TextStyle(fontSize: 20)), - const SizedBox(width: 4), - Text(countryCode, style: TextStyle(color: textMain)), - ], - ), - ), - const SizedBox(width: 8), - Expanded( - child: Container( - height: 48, - decoration: BoxDecoration( - color: inputBg, - borderRadius: BorderRadius.circular(8), - ), - child: TextField( - keyboardType: TextInputType.phone, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly, - LengthLimitingTextInputFormatter(10), - ], - onChanged: (value) { - setState(() { - phoneNumber = value; - error = ''; - }); - }, - style: TextStyle(color: textMain), - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 16), - hintText: 'Enter your number', - hintStyle: TextStyle(color: Color(0xFF999999)), - ), - ), - ), - ), - ], - ), - if (error.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - error, - style: const TextStyle(color: Colors.red, fontSize: 14), - ), - ), - ], - ); - } - - Widget _buildCodeStep(Color textMain, Color textSub) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Enter verification code', - style: TextStyle( - color: textMain, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 8), - Text.rich( - TextSpan( - text: 'We sent a 6-digit code to ', - style: TextStyle(color: textSub, fontSize: 14), - children: [ - TextSpan( - text: '$countryCode $phoneNumber', - style: TextStyle(color: textMain, fontWeight: FontWeight.w600), - ), - const TextSpan(text: '. Enter it below to verify your account.'), - ], - ), - ), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: List.generate(6, (index) { - return SizedBox( - width: 48, - height: 56, - child: TextField( - controller: _codeControllers[index], - focusNode: _codeFocusNodes[index], - keyboardType: TextInputType.number, - textAlign: TextAlign.center, - maxLength: 1, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - color: textMain, - ), - decoration: InputDecoration( - counterText: '', - filled: true, - fillColor: Colors.white, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: error.isNotEmpty - ? Colors.red.withValues(alpha: 0.3) - : (code[index].isNotEmpty - ? textMain - : const Color(0xFFE0E0E0)), - width: 2, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: textMain, width: 2), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: error.isNotEmpty - ? Colors.red.withValues(alpha: 0.3) - : (code[index].isNotEmpty - ? textMain - : const Color(0xFFE0E0E0)), - width: 2, - ), - ), - ), - onChanged: (value) => _handleCodeChange(index, value), - ), - ); - }), - ), - if (error.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 16.0), - child: Center( - child: Text( - error, - style: const TextStyle(color: Colors.red, fontSize: 14), - ), - ), - ), - const SizedBox(height: 24), - Center( - child: GestureDetector( - onTap: _handleResend, - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: error.isNotEmpty ? '' : 'Didn\'t get the code? ', - style: TextStyle( - color: countdown > 0 - ? const Color(0xFF999999) - : Colors.red, - ), - ), - TextSpan( - text: countdown > 0 - ? 'Resend in ${countdown}s' - : 'Resend code', - style: TextStyle( - color: countdown > 0 - ? const Color(0xFF999999) - : Colors.red, - fontWeight: countdown > 0 - ? FontWeight.normal - : FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/profile_setup_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/profile_setup_screen.dart deleted file mode 100644 index a2b20e41..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/auth/profile_setup_screen.dart +++ /dev/null @@ -1,796 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../theme.dart'; -import '../../services/mock_service.dart'; - -class ProfileSetupScreen extends StatefulWidget { - const ProfileSetupScreen({super.key}); - - @override - State createState() => _ProfileSetupScreenState(); -} - -class _ProfileSetupScreenState extends State { - int _currentStep = 0; - bool _isCreatingProfile = false; - - // Form Data - String _fullName = ''; - String _bio = ''; - String? _photoUrl; - final List _preferredLocations = []; - double _maxDistanceMiles = 25; - final List _skills = []; - final List _industries = []; - - // Input Controllers - final TextEditingController _locationController = TextEditingController(); - - // Constants - static const List> _steps = [ - {'id': 'basic', 'title': 'Basic Info', 'icon': LucideIcons.user}, - {'id': 'location', 'title': 'Location', 'icon': LucideIcons.mapPin}, - {'id': 'experience', 'title': 'Experience', 'icon': LucideIcons.briefcase}, - ]; - - static const List _allSkills = [ - 'Food Service', - 'Bartending', - 'Warehouse', - 'Retail', - 'Events', - 'Customer Service', - 'Cleaning', - 'Security', - 'Driving', - 'Cooking', - ]; - - static const List _allIndustries = [ - 'Hospitality', - 'Food Service', - 'Warehouse', - 'Events', - 'Retail', - 'Healthcare', - ]; - - // Logic - void _handleNext() { - if (_currStepValid()) { - if (_currentStep < _steps.length - 1) { - setState(() => _currentStep++); - } else { - _submitProfile(); - } - } - } - - void _handleBack() { - if (_currentStep > 0) { - setState(() => _currentStep--); - } - } - - bool _currStepValid() { - switch (_currentStep) { - case 0: - return _fullName.trim().length >= 2; - case 1: - return _preferredLocations.isNotEmpty; - case 2: - return _skills.isNotEmpty; - default: - return true; - } - } - - Future _submitProfile() async { - setState(() => _isCreatingProfile = true); - - await mockService.createWorkerProfile({ - 'full_name': _fullName, - 'bio': _bio, - 'preferred_locations': _preferredLocations, - 'max_distance_miles': _maxDistanceMiles, - 'skills': _skills, - 'industries': _industries, - }); - - if (mounted) { - context.go('/worker-home'); - } - } - - void _addLocation() { - final loc = _locationController.text.trim(); - if (loc.isNotEmpty && !_preferredLocations.contains(loc)) { - setState(() { - _preferredLocations.add(loc); - _locationController.clear(); - }); - } - } - - void _removeLocation(String loc) { - setState(() { - _preferredLocations.remove(loc); - }); - } - - void _toggleSkill(String skill) { - setState(() { - if (_skills.contains(skill)) { - _skills.remove(skill); - } else { - _skills.add(skill); - } - }); - } - - void _toggleIndustry(String industry) { - setState(() { - if (_industries.contains(industry)) { - _industries.remove(industry); - } else { - _industries.add(industry); - } - }); - } - - @override - Widget build(BuildContext context) { - final double progress = (_currentStep + 1) / _steps.length; - - return Scaffold( - backgroundColor: Colors.white, - body: SafeArea( - child: Column( - children: [ - // Progress Bar - LinearProgressIndicator( - value: progress, - backgroundColor: Colors.grey[100], - color: AppColors.krowBlue, // #0032A0 - minHeight: 4, - ), - - // Header (Back + Step Count) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (_currentStep > 0) - GestureDetector( - onTap: _handleBack, - child: const Row( - children: [ - Icon( - LucideIcons.arrowLeft, - size: 20, - color: AppColors.krowMuted, - ), - SizedBox(width: 8), - Text( - 'Back', - style: TextStyle( - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ) - else - const SizedBox(width: 60), // Placeholder to keep alignment - Text( - 'Step ${_currentStep + 1} of ${_steps.length}', - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - ], - ), - ), - - // Step Indicators - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: List.generate(_steps.length, (index) { - final step = _steps[index]; - final isActive = index == _currentStep; - final isCompleted = index < _currentStep; - - Color bgColor; - Color iconColor; - if (isCompleted) { - bgColor = Colors.green; - iconColor = Colors.white; - } else if (isActive) { - bgColor = AppColors.krowBlue; - iconColor = Colors.white; - } else { - bgColor = Colors.grey[100]!; - iconColor = Colors.grey[400]!; - } - - return Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: bgColor, - shape: BoxShape.circle, - ), - child: Icon( - isCompleted - ? LucideIcons.check - : step['icon'] as IconData, - size: 20, - color: iconColor, - ), - ), - if (index < _steps.length - 1) - Container( - width: 30, - height: 2, - margin: const EdgeInsets.symmetric(horizontal: 4), - color: isCompleted ? Colors.green : Colors.grey[200], - ), - ], - ); - }), - ), - ), - - // Content Area - Expanded( - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: SingleChildScrollView( - key: ValueKey(_currentStep), - padding: const EdgeInsets.all(24), - child: _buildStepContent(), - ), - ), - ), - - // Footer - Container( - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - border: Border(top: BorderSide(color: Colors.grey[100]!)), - ), - child: SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: (_currStepValid() && !_isCreatingProfile) - ? _handleNext - : null, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - disabledBackgroundColor: AppColors.krowBlue.withValues( - alpha: 0.5, - ), - ), - child: _isCreatingProfile - ? const SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - _currentStep == _steps.length - 1 - ? 'Complete Setup' - : 'Continue', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - if (_currentStep < _steps.length - 1) ...const [ - SizedBox(width: 8), - Icon(LucideIcons.arrowRight, size: 20), - ], - ], - ), - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildStepContent() { - switch (_currentStep) { - case 0: - return _buildBasicInfoStep(); - case 1: - return _buildLocationStep(); - case 2: - return _buildExperienceStep(); - default: - return const SizedBox.shrink(); - } - } - - Widget _buildBasicInfoStep() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Let's get to know you", - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - "Tell us a bit about yourself", - style: TextStyle(fontSize: 16, color: AppColors.krowMuted), - ), - const SizedBox(height: 32), - - // Photo Upload - Center( - child: Stack( - children: [ - Container( - width: 112, - height: 112, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.grey[100], - border: Border.all(color: Colors.white, width: 4), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.1), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: _photoUrl != null - ? ClipOval( - child: Image.network(_photoUrl!, fit: BoxFit.cover), - ) - : const Icon( - LucideIcons.user, - size: 48, - color: Colors.grey, - ), - ), - Positioned( - bottom: 0, - right: 0, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: AppColors.krowBlue, - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.2), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: const Icon( - LucideIcons.camera, - color: Colors.white, - size: 20, - ), - ), - ), - ], - ), - ), - const SizedBox(height: 32), - - // Full Name - const Text( - "Full Name *", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - onChanged: (val) => setState(() => _fullName = val), - decoration: InputDecoration( - hintText: "John Smith", - hintStyle: TextStyle(color: Colors.grey[400]), - filled: true, - fillColor: Colors.white, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.grey[200]!), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.grey[200]!), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - const SizedBox(height: 24), - - // Bio - const Text( - "Short Bio", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - TextField( - onChanged: (val) => setState(() => _bio = val), - decoration: InputDecoration( - hintText: "Experienced hospitality professional...", - hintStyle: TextStyle(color: Colors.grey[400]), - filled: true, - fillColor: Colors.white, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.grey[200]!), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.grey[200]!), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - ], - ); - } - - Widget _buildLocationStep() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Where do you want to work?", - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - "Add your preferred work locations", - style: TextStyle(fontSize: 16, color: AppColors.krowMuted), - ), - const SizedBox(height: 32), - - // Add Location input - const Text( - "Add Location *", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: TextField( - controller: _locationController, - onSubmitted: (_) => _addLocation(), - decoration: InputDecoration( - hintText: "City or ZIP code", - hintStyle: TextStyle(color: Colors.grey[400]), - filled: true, - fillColor: Colors.white, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.grey[200]!), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide(color: Colors.grey[200]!), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - ), - ), - ), - const SizedBox(width: 8), - SizedBox( - height: 48, - child: ElevatedButton( - onPressed: _addLocation, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.symmetric(horizontal: 24), - ), - child: const Text("Add"), - ), - ), - ], - ), - - const SizedBox(height: 16), - // Location Badges - if (_preferredLocations.isNotEmpty) - Wrap( - spacing: 8, - runSpacing: 8, - children: _preferredLocations.map((loc) { - return Container( - padding: const EdgeInsets.fromLTRB(12, 8, 8, 8), - decoration: BoxDecoration( - color: AppColors.krowBlue.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(20), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - LucideIcons.mapPin, - size: 14, - color: AppColors.krowBlue, - ), - const SizedBox(width: 6), - Text( - loc, - style: const TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - const SizedBox(width: 6), - GestureDetector( - onTap: () => _removeLocation(loc), - child: const Icon( - LucideIcons.x, - size: 16, - color: AppColors.krowBlue, - ), - ), - ], - ), - ); - }).toList(), - ), - - const SizedBox(height: 32), - // Slider - Text( - "Max Distance: ${_maxDistanceMiles.round()} miles", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - SliderTheme( - data: SliderTheme.of(context).copyWith( - activeTrackColor: AppColors.krowBlue, - inactiveTrackColor: Colors.grey[200], - thumbColor: AppColors.krowBlue, - overlayColor: AppColors.krowBlue.withValues(alpha: 0.1), - trackHeight: 6, - thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 10), - ), - child: Slider( - value: _maxDistanceMiles, - min: 5, - max: 50, - onChanged: (val) => setState(() => _maxDistanceMiles = val), - ), - ), - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("5 mi", style: TextStyle(color: Colors.grey, fontSize: 12)), - Text("50 mi", style: TextStyle(color: Colors.grey, fontSize: 12)), - ], - ), - ), - ], - ); - } - - Widget _buildExperienceStep() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "What are your skills?", - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - "Select all that apply", - style: TextStyle(fontSize: 16, color: AppColors.krowMuted), - ), - const SizedBox(height: 32), - - // Skills - const Text( - "Skills *", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 12), - Wrap( - spacing: 8, - runSpacing: 8, - children: _allSkills.map((skill) { - final isSelected = _skills.contains(skill); - return GestureDetector( - onTap: () => _toggleSkill(skill), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 10, - ), - decoration: BoxDecoration( - color: isSelected ? AppColors.krowBlue : Colors.white, - borderRadius: BorderRadius.circular(30), - border: Border.all( - color: isSelected ? AppColors.krowBlue : Colors.grey[300]!, - width: isSelected ? 0 : 1, - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (isSelected) - const Padding( - padding: EdgeInsets.only(right: 6), - child: Icon( - LucideIcons.check, - size: 16, - color: Colors.white, - ), - ), - Text( - skill, - style: TextStyle( - color: isSelected ? Colors.white : Colors.grey[700], - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - ], - ), - ), - ); - }).toList(), - ), - - const SizedBox(height: 32), - // Industries - const Text( - "Preferred Industries", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 12), - Wrap( - spacing: 8, - runSpacing: 8, - children: _allIndustries.map((industry) { - final isSelected = _industries.contains(industry); - const activeBg = Color(0xFFF7E600); // React prop: bg-[#F7E600] - const activeText = Color(0xFF333F48); // React prop: text-[#333F48] - const activeBorder = Color(0xFFF7E600); - - return GestureDetector( - onTap: () => _toggleIndustry(industry), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 10, - ), - decoration: BoxDecoration( - color: isSelected ? activeBg : Colors.white, - borderRadius: BorderRadius.circular(30), - border: Border.all( - color: isSelected ? activeBorder : Colors.grey[300]!, - width: isSelected ? 0 : 1, - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (isSelected) - const Padding( - padding: EdgeInsets.only(right: 6), - child: Icon( - LucideIcons.check, - size: 16, - color: activeText, - ), - ), - Text( - industry, - style: TextStyle( - color: isSelected ? activeText : Colors.grey[700], - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - ], - ), - ), - ); - }).toList(), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/availability_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/availability_screen.dart deleted file mode 100644 index 313b5d95..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/availability_screen.dart +++ /dev/null @@ -1,784 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class AvailabilityScreen extends StatefulWidget { - const AvailabilityScreen({super.key}); - - @override - State createState() => _AvailabilityScreenState(); -} - -class _AvailabilityScreenState extends State { - late DateTime _currentWeekStart; - late DateTime _selectedDate; - - // Mock Availability State - // Map of day name (lowercase) to availability status - Map _availability = { - 'monday': true, - 'tuesday': true, - 'wednesday': true, - 'thursday': true, - 'friday': true, - 'saturday': false, - 'sunday': false, - }; - - // Map of day name to time slot map - Map> _timeSlotAvailability = { - 'monday': {'morning': true, 'afternoon': true, 'evening': true}, - 'tuesday': {'morning': true, 'afternoon': true, 'evening': true}, - 'wednesday': {'morning': true, 'afternoon': true, 'evening': true}, - 'thursday': {'morning': true, 'afternoon': true, 'evening': true}, - 'friday': {'morning': true, 'afternoon': true, 'evening': true}, - 'saturday': {'morning': false, 'afternoon': false, 'evening': false}, - 'sunday': {'morning': false, 'afternoon': false, 'evening': false}, - }; - - final List _dayNames = [ - 'sunday', - 'monday', - 'tuesday', - 'wednesday', - 'thursday', - 'friday', - 'saturday', - ]; - - final List> _timeSlots = [ - { - 'slotId': 'morning', - 'label': 'Morning', - 'timeRange': '4:00 AM - 12:00 PM', - 'icon': LucideIcons.sunrise, - 'bg': const Color(0xFFE6EBF9), // bg-[#0032A0]/10 - 'iconColor': const Color(0xFF0032A0), - }, - { - 'slotId': 'afternoon', - 'label': 'Afternoon', - 'timeRange': '12:00 PM - 6:00 PM', - 'icon': LucideIcons.sun, - 'bg': const Color(0xFFCCD6EC), // bg-[#0032A0]/20 - 'iconColor': const Color(0xFF0032A0), - }, - { - 'slotId': 'evening', - 'label': 'Evening', - 'timeRange': '6:00 PM - 12:00 AM', - 'icon': LucideIcons.moon, - 'bg': const Color(0xFFEBEDEE), // bg-[#333F48]/10 - 'iconColor': const Color(0xFF333F48), - }, - ]; - - @override - void initState() { - super.initState(); - final today = DateTime.now(); - // Calculate start of week (assuming week starts on Sunday based on typical calendar logic, - // but React code navigates based on diff. Let's match React logic: - // const diff = today.getDate() - day + (day === 0 ? -6 : 1); -> This suggests Monday start actually? - // React: day === 0 (Sun) ? -6 : 1. If today is Mon(1), 1-1+1 = 1 (Mon). If Sun(0), 0-0-6 = -6 (Prev Mon). - // So React week starts Monday. - - // Dart equivalent for Monday start: - final day = today.weekday; // Mon=1, Sun=7 - final diff = day - 1; - _currentWeekStart = today.subtract(Duration(days: diff)); - // Reset time to midnight - _currentWeekStart = DateTime( - _currentWeekStart.year, - _currentWeekStart.month, - _currentWeekStart.day, - ); - - _selectedDate = today; - } - - List _getWeekDates() { - return List.generate( - 7, - (index) => _currentWeekStart.add(Duration(days: index)), - ); - } - - String _formatDay(DateTime date) { - return DateFormat('EEE').format(date); - } - - bool _isToday(DateTime date) { - final now = DateTime.now(); - return date.year == now.year && - date.month == now.month && - date.day == now.day; - } - - bool _isSelected(DateTime date) { - return date.year == _selectedDate.year && - date.month == _selectedDate.month && - date.day == _selectedDate.day; - } - - void _navigateWeek(int direction) { - setState(() { - _currentWeekStart = _currentWeekStart.add(Duration(days: direction * 7)); - }); - } - - void _toggleDayAvailability(String dayName) { - setState(() { - _availability[dayName] = !(_availability[dayName] ?? false); - // React code also updates mutation. We mock this. - }); - } - - String _getDayKey(DateTime date) { - // DateTime.weekday: Mon=1...Sun=7. - // _dayNames array: 0=Sun, 1=Mon... - // React code: date.getDay() -> 0=Sun, 1=Mon. - // So we use date.weekday % 7 to match 0-6 index for Sunday-Saturday if we want to index _dayNames correctly? - // Wait, React uses: dayNames = ['sunday', 'monday', ...]. - // And getDay() returns 0 for Sunday. So dayNames[0] is 'sunday'. - // Dart weekday: 7 is Sunday. 7 % 7 = 0. - return _dayNames[date.weekday % 7]; - } - - void _toggleTimeSlot(String slotId) { - final dayKey = _getDayKey(_selectedDate); - final currentDaySlots = - _timeSlotAvailability[dayKey] ?? - {'morning': true, 'afternoon': true, 'evening': true}; - final newValue = !(currentDaySlots[slotId] ?? true); - - setState(() { - _timeSlotAvailability[dayKey] = {...currentDaySlots, slotId: newValue}; - }); - } - - bool _isTimeSlotActive(String slotId) { - final dayKey = _getDayKey(_selectedDate); - final daySlots = _timeSlotAvailability[dayKey]; - if (daySlots == null) return true; - return daySlots[slotId] != false; - } - - String _getMonthYear() { - final middleDate = _currentWeekStart.add(const Duration(days: 3)); - return DateFormat('MMMM yyyy').format(middleDate); - } - - void _quickSet(String type) { - Map newAvailability = {}; - - switch (type) { - case 'all': - for (var day in _dayNames) newAvailability[day] = true; - break; - case 'weekdays': - for (var day in _dayNames) - newAvailability[day] = (day != 'saturday' && day != 'sunday'); - break; - case 'weekends': - for (var day in _dayNames) - newAvailability[day] = (day == 'saturday' || day == 'sunday'); - break; - case 'clear': - for (var day in _dayNames) newAvailability[day] = false; - break; - } - - setState(() { - _availability = newAvailability; - }); - } - - @override - Widget build(BuildContext context) { - final selectedDayKey = _getDayKey(_selectedDate); - final isSelectedDayAvailable = _availability[selectedDayKey] ?? false; - final weekDates = _getWeekDates(); - - return Scaffold( - backgroundColor: const Color( - 0xFFFAFBFC, - ), // slate-50 to white gradient approximation - body: SingleChildScrollView( - padding: const EdgeInsets.only(bottom: 100), - child: Column( - children: [ - _buildHeader(), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _buildQuickSet(), - const SizedBox(height: 24), - _buildWeekNavigation(weekDates), - const SizedBox(height: 24), - _buildSelectedDayAvailability( - selectedDayKey, - isSelectedDayAvailable, - ), - const SizedBox(height: 24), - _buildInfoCard(), - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader() { - return Container( - padding: const EdgeInsets.fromLTRB(20, 60, 20, 20), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - IconButton( - icon: const Icon( - LucideIcons.arrowLeft, - color: AppColors.krowCharcoal, - ), - onPressed: () => context.pop(), - ), - const SizedBox(width: 12), - // The rest of the original content in the `Row` will follow here. - // This part of the replacement will maintain the avatar and text content. - // Note: The avatar and text were originally part of the same `Row` as the `GestureDetector`. - // I will place them back into a nested `Row` to maintain the visual structure. - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - border: Border.all( - color: AppColors.krowBlue.withOpacity(0.2), - width: 2, - ), - shape: BoxShape.circle, - ), - child: Center( - child: CircleAvatar( - backgroundColor: AppColors.krowBlue.withOpacity( - 0.1, - ), - radius: 18, - child: const Text( - 'K', // Mock initial - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ), - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'My Availability', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - 'Set when you can work', - style: TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - ], - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.calendar, - color: AppColors.krowBlue, - size: 20, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildQuickSet() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Quick Set Availability', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF333F48), - ), - ), - const SizedBox(height: 12), - Row( - children: [ - Expanded( - child: _buildQuickSetButton('All Week', () => _quickSet('all')), - ), - const SizedBox(width: 8), - Expanded( - child: _buildQuickSetButton( - 'Weekdays', - () => _quickSet('weekdays'), - ), - ), - const SizedBox(width: 8), - Expanded( - child: _buildQuickSetButton( - 'Weekends', - () => _quickSet('weekends'), - ), - ), - const SizedBox(width: 8), - Expanded( - child: _buildQuickSetButton( - 'Clear All', - () => _quickSet('clear'), - isDestructive: true, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildQuickSetButton( - String label, - VoidCallback onTap, { - bool isDestructive = false, - }) { - return SizedBox( - height: 32, - child: OutlinedButton( - onPressed: onTap, - style: OutlinedButton.styleFrom( - padding: EdgeInsets.zero, - side: BorderSide( - color: isDestructive - ? Colors.red.withOpacity(0.2) - : AppColors.krowBlue.withOpacity(0.2), - ), - backgroundColor: - Colors.transparent, // React has hover effect, plain here - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - foregroundColor: isDestructive ? Colors.red : AppColors.krowBlue, - ), - child: Text( - label, - style: const TextStyle(fontSize: 10, fontWeight: FontWeight.w500), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ); - } - - Widget _buildWeekNavigation(List weekDates) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - // Nav Header - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _buildNavButton( - LucideIcons.chevronLeft, - () => _navigateWeek(-1), - ), - Text( - _getMonthYear(), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - _buildNavButton( - LucideIcons.chevronRight, - () => _navigateWeek(1), - ), - ], - ), - ), - // Days Row - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: weekDates.map((date) => _buildDayItem(date)).toList(), - ), - ], - ), - ); - } - - Widget _buildNavButton(IconData icon, VoidCallback onTap) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 32, - height: 32, - decoration: const BoxDecoration( - color: Color(0xFFF1F5F9), // slate-100 - shape: BoxShape.circle, - ), - child: Icon(icon, size: 20, color: AppColors.krowMuted), - ), - ); - } - - Widget _buildDayItem(DateTime date) { - final isSelected = _isSelected(date); - final dayKey = _getDayKey(date); - final isAvailable = _availability[dayKey] ?? false; - final isToday = _isToday(date); - - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _selectedDate = date), - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 2), - padding: const EdgeInsets.symmetric(vertical: 12), - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue - : (isAvailable - ? const Color(0xFFECFDF5) - : const Color(0xFFF8FAFC)), // emerald-50 or slate-50 - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: isSelected - ? AppColors.krowBlue - : (isAvailable - ? const Color(0xFFA7F3D0) - : Colors.transparent), // emerald-200 - ), - boxShadow: isSelected - ? [ - BoxShadow( - color: AppColors.krowBlue.withOpacity(0.3), - blurRadius: 8, - offset: const Offset(0, 4), - ), - ] - : null, - ), - child: Stack( - clipBehavior: Clip.none, - alignment: Alignment.center, - children: [ - Column( - children: [ - Text( - date.day.toString().padLeft(2, '0'), - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : (isAvailable - ? const Color(0xFF047857) - : AppColors.krowMuted), // emerald-700 - ), - ), - const SizedBox(height: 2), - Text( - _formatDay(date), - style: TextStyle( - fontSize: 10, - color: isSelected - ? Colors.white.withOpacity(0.8) - : (isAvailable - ? const Color(0xFF047857) - : AppColors.krowMuted), - ), - ), - ], - ), - if (isToday && !isSelected) - Positioned( - bottom: -8, - child: Container( - width: 6, - height: 6, - decoration: const BoxDecoration( - color: AppColors.krowBlue, - shape: BoxShape.circle, - ), - ), - ), - ], - ), - ), - ), - ); - } - - Widget _buildSelectedDayAvailability( - String selectedDayKey, - bool isAvailable, - ) { - final dateStr = DateFormat('EEEE, MMM d').format(_selectedDate); - - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - // Header Row - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - dateStr, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - Text( - isAvailable ? 'You are available' : 'Not available', - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - Switch( - value: isAvailable, - onChanged: (val) => _toggleDayAvailability(selectedDayKey), - activeColor: AppColors.krowBlue, - ), - ], - ), - - const SizedBox(height: 16), - - // Time Slots - ..._timeSlots.map((slot) { - final isActive = _isTimeSlotActive(slot['slotId']); - // Determine styles based on state - final isEnabled = - isAvailable; // If day is off, slots are disabled visually - - // Container style - Color bgColor; - Color borderColor; - - if (!isEnabled) { - bgColor = const Color(0xFFF8FAFC); // slate-50 - borderColor = const Color(0xFFF1F5F9); // slate-100 - } else if (isActive) { - bgColor = AppColors.krowBlue.withOpacity(0.05); - borderColor = AppColors.krowBlue.withOpacity(0.2); - } else { - bgColor = const Color(0xFFF8FAFC); // slate-50 - borderColor = const Color(0xFFE2E8F0); // slate-200 - } - - // Text colors - final titleColor = (isEnabled && isActive) - ? AppColors.krowCharcoal - : AppColors.krowMuted; - final subtitleColor = (isEnabled && isActive) - ? AppColors.krowMuted - : Colors.grey.shade400; - - return GestureDetector( - onTap: isEnabled ? () => _toggleTimeSlot(slot['slotId']) : null, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: bgColor, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: borderColor, width: 2), - ), - child: Row( - children: [ - // Icon - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: slot['bg'], - borderRadius: BorderRadius.circular(12), - ), - child: Icon( - slot['icon'], - color: slot['iconColor'], - size: 20, - ), - ), - const SizedBox(width: 12), - // Text - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - slot['label'], - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: titleColor, - ), - ), - Text( - slot['timeRange'], - style: TextStyle( - fontSize: 12, - color: subtitleColor, - ), - ), - ], - ), - ), - // Checkbox indicator - if (isEnabled && isActive) - Container( - width: 24, - height: 24, - decoration: const BoxDecoration( - color: AppColors.krowBlue, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.check, - size: 16, - color: Colors.white, - ), - ) - else if (isEnabled && !isActive) - Container( - width: 24, - height: 24, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: const Color(0xFFCBD5E1), - width: 2, - ), // slate-300 - ), - ), - ], - ), - ), - ); - }).toList(), - ], - ), - ); - } - - Widget _buildInfoCard() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.05), - borderRadius: BorderRadius.circular(12), - ), - child: const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(LucideIcons.clock, size: 20, color: AppColors.krowBlue), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Auto-Match uses your availability', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - SizedBox(height: 2), - Text( - "When enabled, you'll only be matched with shifts during your available times.", - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/benefits_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/benefits_screen.dart deleted file mode 100644 index ed8b728f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/benefits_screen.dart +++ /dev/null @@ -1,534 +0,0 @@ -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class BenefitsScreen extends StatefulWidget { - const BenefitsScreen({super.key}); - - @override - State createState() => _BenefitsScreenState(); -} - -class _BenefitsScreenState extends State { - final List> _benefitsData = [ - { - 'id': 'sick', - 'title': 'Sick Days', - 'currentHours': 10, - 'totalHours': 40, - 'color': const Color(0xFF10B981), - 'description': 'You need at least 8 hours to request sick leave', - 'history': [ - {'date': '1 Jan, 2024', 'status': 'Pending'}, - {'date': '28 Jan, 2024', 'status': 'Submitted'}, - {'date': '5 Feb, 2024', 'status': 'Submitted'}, - {'date': '28 Jan, 2024', 'status': 'Submitted'}, - {'date': '5 Feb, 2024', 'status': 'Submitted'}, - ], - 'requestLabel': 'Request Payment for Sick Leave', - }, - { - 'id': 'vacation', - 'title': 'Vacation', - 'currentHours': 40, - 'totalHours': 40, - 'color': const Color(0xFF10B981), - 'description': 'You need 40 hours to claim vacation pay', - 'history': [], - 'requestLabel': 'Request Payment for Vacation', - 'notice': - 'Listed certificates are mandatory for employees. If the employee does not have the complete certificates, they can\'t proceed with their registration.', - }, - { - 'id': 'holidays', - 'title': 'Holidays', - 'currentHours': 24, - 'totalHours': 24, - 'color': const Color(0xFF10B981), - 'description': 'Pay holidays: Thanksgiving, Christmas, New Year', - 'history': [], - 'requestLabel': 'Request Payment for Holiday', - 'notice': - 'Listed certificates are mandatory for employees. If the employee does not have the complete certificates, they can\'t proceed with their registration.', - }, - ]; - - bool _showSuccess = false; - String _successType = ''; - - void _handleRequest(Map benefit) { - setState(() { - _successType = benefit['title']; - _showSuccess = true; - }); - } - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - Scaffold( - backgroundColor: AppColors.krowBackground, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon( - LucideIcons.chevronLeft, - color: AppColors.krowMuted, - ), - onPressed: () => - context.canPop() ? context.pop() : context.go('/worker-home'), - ), - title: const Text( - 'Your Benefits Overview', - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - centerTitle: true, - bottom: PreferredSize( - preferredSize: const Size.fromHeight(24), - child: Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Text( - 'Manage and track your earned benefits here', - style: TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - ), - ), - shape: const Border(bottom: BorderSide(color: Color(0xFFF1F5F9))), - ), - body: ListView.separated( - padding: const EdgeInsets.all(20), - itemCount: _benefitsData.length, - separatorBuilder: (context, index) => const SizedBox(height: 16), - itemBuilder: (context, index) { - return _BenefitCard( - benefit: _benefitsData[index], - onRequest: () => _handleRequest(_benefitsData[index]), - ); - }, - ), - ), - if (_showSuccess) - _SuccessModal( - type: _successType, - onClose: () => setState(() => _showSuccess = false), - ), - ], - ); - } -} - -class _BenefitCard extends StatefulWidget { - final Map benefit; - final VoidCallback onRequest; - - const _BenefitCard({required this.benefit, required this.onRequest}); - - @override - State<_BenefitCard> createState() => _BenefitCardState(); -} - -class _BenefitCardState extends State<_BenefitCard> { - bool _expanded = false; - - @override - Widget build(BuildContext context) { - final history = widget.benefit['history'] as List; - final hasHistory = history.isNotEmpty; - final notice = widget.benefit['notice'] as String?; - - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: const Color(0xFFF1F5F9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.02), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _CircularProgress( - current: widget.benefit['currentHours'], - total: widget.benefit['totalHours'], - color: widget.benefit['color'], - ), - const SizedBox(width: 16), - Expanded( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.benefit['title'], - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 2), - Text( - widget.benefit['description'], - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - const Icon( - LucideIcons.info, - size: 20, - color: Color(0xFFCBD5E1), - ), - ], - ), - ), - ], - ), - if (hasHistory) ...[ - const SizedBox(height: 16), - InkWell( - onTap: () => setState(() => _expanded = !_expanded), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'SICK LEAVE HISTORY', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowMuted, - letterSpacing: 0.5, - ), - ), - Icon( - _expanded - ? LucideIcons.chevronUp - : LucideIcons.chevronDown, - size: 16, - color: AppColors.krowMuted, - ), - ], - ), - ), - ), - AnimatedCrossFade( - firstChild: const SizedBox.shrink(), - secondChild: Column( - children: history.map((item) { - final isPending = item['status'] == 'Pending'; - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - item['date'], - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 2, - ), - decoration: BoxDecoration( - color: isPending - ? const Color(0xFFF1F5F9) - : const Color(0xFFECFDF5), - borderRadius: BorderRadius.circular(12), - border: isPending - ? Border.all( - color: const Color(0xFFCBD5E1), - ) - : null, - ), - child: Text( - item['status'], - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: isPending - ? AppColors.krowMuted - : const Color(0xFF047857), - ), - ), - ), - ], - ), - ); - }).toList(), - ), - crossFadeState: _expanded - ? CrossFadeState.showSecond - : CrossFadeState.showFirst, - duration: const Duration(milliseconds: 200), - ), - ], - if (notice != null) ...[ - const SizedBox(height: 16), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFECFDF5), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - LucideIcons.checkCircle, - size: 16, - color: Color(0xFF10B981), - ), - const SizedBox(width: 8), - Expanded( - child: Text( - notice, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF047857), - ), - ), - ), - ], - ), - ), - ], - ], - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), - child: SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: widget.onRequest, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0032A0), - foregroundColor: Colors.white, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Text( - widget.benefit['requestLabel'], - style: const TextStyle(fontWeight: FontWeight.w500), - ), - ), - ), - ), - ], - ), - ); - } -} - -class _CircularProgress extends StatelessWidget { - final int current; - final int total; - final Color color; - final double size; - - const _CircularProgress({ - required this.current, - required this.total, - required this.color, - this.size = 64, - }); - - @override - Widget build(BuildContext context) { - return SizedBox( - width: size, - height: size, - child: Stack( - fit: StackFit.expand, - children: [ - Transform.rotate( - angle: -pi / 2, - child: CustomPaint( - painter: _CircularProgressPainter( - progress: current / total, - color: color, - strokeWidth: 5, - ), - ), - ), - Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - '$current/$total', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'hours', - style: TextStyle(fontSize: 10, color: Color(0xFF94A3B8)), - ), - ], - ), - ), - ], - ), - ); - } -} - -class _CircularProgressPainter extends CustomPainter { - final double progress; - final Color color; - final double strokeWidth; - - _CircularProgressPainter({ - required this.progress, - required this.color, - required this.strokeWidth, - }); - - @override - void paint(Canvas canvas, Size size) { - final center = Offset(size.width / 2, size.height / 2); - final radius = (size.width - strokeWidth) / 2; - - final bgPaint = Paint() - ..color = const Color(0xFFE2E8F0) - ..strokeWidth = strokeWidth - ..style = PaintingStyle.stroke; - - canvas.drawCircle(center, radius, bgPaint); - - final fgPaint = Paint() - ..color = color - ..strokeWidth = strokeWidth - ..style = PaintingStyle.stroke - ..strokeCap = StrokeCap.round; - - canvas.drawArc( - Rect.fromCircle(center: center, radius: radius), - 0, - 2 * pi * progress, - false, - fgPaint, - ); - } - - @override - bool shouldRepaint(covariant _CircularProgressPainter oldDelegate) { - return oldDelegate.progress != progress || oldDelegate.color != color; - } -} - -class _SuccessModal extends StatelessWidget { - final String type; - final VoidCallback onClose; - - const _SuccessModal({required this.type, required this.onClose}); - - @override - Widget build(BuildContext context) { - return Container( - color: Colors.black.withOpacity(0.5), - child: Center( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Container( - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: Color(0xFFF1F5F9), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.thumbsUp, - size: 32, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 20), - const Text( - 'Request Submitted', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - Text( - 'Your ${type.toLowerCase()} request has been submitted successfully. You\'ll be notified once it\'s processed', - textAlign: TextAlign.center, - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 16, - ), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: onClose, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0032A0), - foregroundColor: Colors.white, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text('Back to Profile'), - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/clock_in_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/clock_in_screen.dart deleted file mode 100644 index 9079b2e8..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/clock_in_screen.dart +++ /dev/null @@ -1,796 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import '../../theme.dart'; -import '../../widgets/clock_in/attendance_card.dart'; -import '../../widgets/clock_in/date_selector.dart'; -import '../../widgets/clock_in/swipe_to_check_in.dart'; -import '../../widgets/clock_in/lunch_break_modal.dart'; -import '../../widgets/clock_in/commute_tracker.dart'; -import '../../models/shift.dart'; - -class ClockInScreen extends StatefulWidget { - const ClockInScreen({super.key}); - - @override - State createState() => _ClockInScreenState(); -} - -class _ClockInScreenState extends State { - DateTime _selectedDate = DateTime.now(); - bool _isCheckedIn = false; - DateTime? _checkInTime; - DateTime? _checkOutTime; - String _checkInMode = 'swipe'; // 'swipe' or 'nfc' - - // Mock data matching React - // Setting shift for tomorrow to make CommuteTracker visible - final Shift? _todayShift = Shift( - id: '1', - title: 'Warehouse Assistant', - clientName: 'Amazon Warehouse', - logoUrl: - 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/Amazon_2024.svg/500px-Amazon_2024.svg.png', - hourlyRate: 22.50, - date: DateFormat('yyyy-MM-dd').format( - DateTime.now().add(const Duration(hours: 2)), - ), // Shift in 2 hours to trigger commute window - startTime: DateFormat( - 'HH:mm', - ).format(DateTime.now().add(const Duration(hours: 2))), - endTime: DateFormat( - 'HH:mm', - ).format(DateTime.now().add(const Duration(hours: 10))), - location: 'San Francisco, CA', - locationAddress: '123 Market St, San Francisco, CA 94105', - status: 'assigned', - createdDate: DateTime.now() - .subtract(const Duration(days: 2)) - .toIso8601String(), - latitude: 37.7749, - longitude: -122.4194, - description: 'General warehouse duties including packing and sorting.', - managers: [], - ); - - final List> _activityLog = [ - { - 'date': DateTime.now().subtract(const Duration(days: 1)), - 'start': '09:00 AM', - 'end': '05:00 PM', - 'hours': '8h', - }, - { - 'date': DateTime.now().subtract(const Duration(days: 2)), - 'start': '09:00 AM', - 'end': '05:00 PM', - 'hours': '8h', - }, - { - 'date': DateTime.now().subtract(const Duration(days: 3)), - 'start': '09:00 AM', - 'end': '05:00 PM', - 'hours': '8h', - }, - ]; - - @override - Widget build(BuildContext context) { - // Format times for display - final checkInStr = _checkInTime != null - ? DateFormat('h:mm a').format(_checkInTime!) - : '--:-- --'; - final checkOutStr = _checkOutTime != null - ? DateFormat('h:mm a').format(_checkOutTime!) - : '--:-- --'; - - return Scaffold( - body: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xFFF8FAFC), // slate-50 - Colors.white, - ], - ), - ), - child: SafeArea( - child: SingleChildScrollView( - padding: const EdgeInsets.only(bottom: 100), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildHeader(), - - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - // Commute Tracker (shows before date selector when applicable) - if (_todayShift != null) - CommuteTracker( - shift: _todayShift, - hasLocationConsent: false, // Mock value - isCommuteModeOn: false, // Mock value - distanceMeters: 500, // Mock value for demo - etaMinutes: 8, // Mock value for demo - ), - - // Date Selector - DateSelector( - selectedDate: _selectedDate, - onSelect: (date) => - setState(() => _selectedDate = date), - shiftDates: [ - DateFormat('yyyy-MM-dd').format(DateTime.now()), - ], - ), - const SizedBox(height: 20), - - // Today Attendance Section - const Align( - alignment: Alignment.centerLeft, - child: Text( - "Today Attendance", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ), - const SizedBox(height: 12), - GridView.count( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - crossAxisCount: 2, - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.0, - children: [ - AttendanceCard( - type: AttendanceType.checkin, - title: "Check In", - value: checkInStr, - subtitle: _checkInTime != null - ? "On Time" - : "Pending", - scheduledTime: "09:00 AM", - ), - AttendanceCard( - type: AttendanceType.checkout, - title: "Check Out", - value: checkOutStr, - subtitle: _checkOutTime != null - ? "Go Home" - : "Pending", - scheduledTime: "05:00 PM", - ), - AttendanceCard( - type: AttendanceType.breaks, - title: "Break Time", - value: "00:30 min", - subtitle: "Scheduled 00:30 min", - ), - const AttendanceCard( - type: AttendanceType.days, - title: "Total Days", - value: "28", - subtitle: "Working Days", - ), - ], - ), - const SizedBox(height: 24), - - // Your Activity Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - "Your Activity", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - GestureDetector( - onTap: () => context.push('/shifts'), - child: const Row( - children: [ - Text( - "View all", - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.w500, - ), - ), - Icon( - LucideIcons.chevronRight, - size: 16, - color: AppColors.krowBlue, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - - // Check-in Mode Toggle - const Align( - alignment: Alignment.centerLeft, - child: Text( - "Check-in Method", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), // slate-700 - ), - ), - ), - const SizedBox(height: 8), - Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), // slate-100 - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - _buildModeTab("Swipe", LucideIcons.mapPin, 'swipe'), - _buildModeTab("NFC Tap", LucideIcons.wifi, 'nfc'), - ], - ), - ), - const SizedBox(height: 16), - - // Selected Shift Info Card - if (_todayShift != null) - Container( - padding: const EdgeInsets.all(12), - margin: const EdgeInsets.only(bottom: 16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFE2E8F0), - ), // slate-200 - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "TODAY'S SHIFT", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: AppColors.krowBlue, - letterSpacing: 0.5, - ), - ), - const SizedBox(height: 2), - Text( - _todayShift!.title, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF1E293B), // slate-800 - ), - ), - Text( - "${_todayShift!.clientName} • ${_todayShift!.location}", - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - "9:00 AM - 5:00 PM", - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF475569), // slate-600 - ), - ), - Text( - "\$${_todayShift!.hourlyRate}/hr", - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: AppColors.krowBlue, - ), - ), - ], - ), - ], - ), - ), - - // Swipe To Check In / Checked Out State / No Shift State - if (_todayShift != null && !(_checkOutTime != null)) ...[ - SwipeToCheckIn( - isCheckedIn: _isCheckedIn, - mode: _checkInMode, - onCheckIn: () async { - // Show NFC dialog if mode is 'nfc' - if (_checkInMode == 'nfc') { - await _showNFCDialog(); - } else { - await Future.delayed(const Duration(seconds: 1)); - setState(() { - _isCheckedIn = true; - _checkInTime = DateTime.now(); - }); - } - }, - onCheckOut: () { - setState(() { - _checkOutTime = DateTime.now(); - }); - showDialog( - context: context, - builder: (context) => LunchBreakDialog( - onComplete: () { - setState(() { - _isCheckedIn = false; - _checkInTime = null; - _checkOutTime = null; - }); - }, - ), - ); - }, - ), - ] else if (_todayShift != null && - _checkOutTime != null) ...[ - // Shift Completed State - Container( - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: const Color(0xFFECFDF5), // emerald-50 - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: const Color(0xFFA7F3D0), - ), // emerald-200 - ), - child: Column( - children: [ - Container( - width: 48, - height: 48, - decoration: const BoxDecoration( - color: Color(0xFFD1FAE5), // emerald-100 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.check, - color: Color(0xFF059669), // emerald-600 - size: 24, - ), - ), - const SizedBox(height: 12), - const Text( - "Shift Completed!", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF065F46), // emerald-800 - ), - ), - const SizedBox(height: 4), - const Text( - "Great work today", - style: TextStyle( - fontSize: 14, - color: Color(0xFF059669), // emerald-600 - ), - ), - ], - ), - ), - ] else ...[ - // No Shift State - Container( - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), // slate-100 - borderRadius: BorderRadius.circular(16), - ), - child: Column( - children: [ - const Text( - "No confirmed shifts for today", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF475569), // slate-600 - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 4), - const Text( - "Accept a shift to clock in", - style: TextStyle( - fontSize: 14, - color: Color(0xFF64748B), // slate-500 - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - ], - - // Checked In Banner - if (_isCheckedIn && _checkInTime != null) ...[ - const SizedBox(height: 12), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFECFDF5), // emerald-50 - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFA7F3D0), - ), // emerald-200 - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Checked in at", - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF059669), - ), - ), - Text( - DateFormat('h:mm a').format(_checkInTime!), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Color(0xFF065F46), - ), - ), - ], - ), - Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Color(0xFFD1FAE5), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.check, - color: Color(0xFF059669), - ), - ), - ], - ), - ), - ], - - const SizedBox(height: 16), - - // Recent Activity List - ..._activityLog.map( - (activity) => Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFF8F9FA), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFF1F5F9), - ), // slate-100 - ), - child: Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.mapPin, - color: AppColors.krowBlue, - size: 20, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - DateFormat( - 'MMM d', - ).format(activity['date'] as DateTime), - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF0F172A), // slate-900 - ), - ), - Text( - "${activity['start']} - ${activity['end']}", - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ), - Text( - activity['hours'] as String, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowBlue, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - ); - } - - Widget _buildModeTab(String label, IconData icon, String value) { - final isSelected = _checkInMode == value; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _checkInMode = value), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(8), - boxShadow: isSelected - ? [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ] - : [], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - icon, - size: 16, - color: isSelected ? Colors.black : Colors.grey, - ), - const SizedBox(width: 6), - Text( - label, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isSelected ? Colors.black : Colors.grey, - ), - ), - ], - ), - ), - ), - ); - } - - Widget _buildHeader() { - return Padding( - padding: const EdgeInsets.fromLTRB(20, 24, 20, 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: AppColors.krowBlue.withOpacity(0.2), - width: 2, - ), - ), - child: CircleAvatar( - backgroundColor: AppColors.krowBlue.withOpacity(0.1), - child: const Text( - 'K', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Good Morning', - style: TextStyle(color: AppColors.krowMuted, fontSize: 12), - ), - Text( - 'Krower', - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - Text( - 'Warehouse Assistant', - style: TextStyle(color: AppColors.krowMuted, fontSize: 12), - ), - ], - ), - ], - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular( - 20, - ), // Rounded full for this page per design - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: const Icon( - LucideIcons.bell, - color: AppColors.krowMuted, - size: 20, - ), - ), - ], - ), - ); - } - - Future _showNFCDialog() async { - bool scanned = false; - - await showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext dialogContext) { - return StatefulBuilder( - builder: (context, setState) { - return AlertDialog( - title: Text(scanned ? 'Tag Scanned!' : 'Scan NFC Tag'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 96, - height: 96, - decoration: BoxDecoration( - color: scanned - ? Colors.green.shade50 - : Colors.blue.shade50, - shape: BoxShape.circle, - ), - child: Icon( - scanned ? LucideIcons.check : LucideIcons.nfc, - size: 48, - color: scanned - ? Colors.green.shade600 - : Colors.blue.shade600, - ), - ), - const SizedBox(height: 24), - Text( - scanned ? 'Processing check-in...' : 'Ready to scan', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - const SizedBox(height: 8), - Text( - scanned - ? 'Please wait...' - : 'Hold your phone near the NFC tag at the clock-in station', - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Colors.grey.shade600), - ), - if (!scanned) ...[ - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton.icon( - onPressed: () async { - setState(() { - scanned = true; - }); - // Simulate NFC scan delay - await Future.delayed( - const Duration(milliseconds: 1000), - ); - Navigator.of(dialogContext).pop(); - // Perform check-in - if (mounted) { - this.setState(() { - _isCheckedIn = true; - _checkInTime = DateTime.now(); - }); - } - }, - icon: const Icon(LucideIcons.nfc, size: 24), - label: const Text( - 'Tap to Scan', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ), - ], - ], - ), - ); - }, - ); - }, - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/early_pay_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/early_pay_screen.dart deleted file mode 100644 index 1be026b4..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/early_pay_screen.dart +++ /dev/null @@ -1,899 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../theme.dart'; - -class EarlyPayScreen extends StatefulWidget { - const EarlyPayScreen({super.key}); - - @override - State createState() => _EarlyPayScreenState(); -} - -class _EarlyPayScreenState extends State { - // State - String _enrollmentStep = 'info'; // info, terms, complete - bool _isEnrolled = false; - bool _agreedToTerms = false; - double _requestAmount = 0; - bool _showConfirmation = false; - bool _isLoading = false; - - // Mock Data - final double _availableAmount = 285.0; - - double get _serviceFee => _requestAmount * 0.05; - double get _netAmount => _requestAmount - _serviceFee; - - void _handleEnroll() async { - setState(() => _isLoading = true); - await Future.delayed(const Duration(seconds: 1)); // Mock API - setState(() { - _isLoading = false; - _enrollmentStep = 'complete'; - _isEnrolled = true; // For next time - }); - } - - void _handleRequest() async { - setState(() => _isLoading = true); - await Future.delayed(const Duration(seconds: 1)); // Mock API - setState(() { - _isLoading = false; - _showConfirmation = true; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), - body: Stack( - children: [ - Column( - children: [ - _buildHeader(), - Expanded( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 24, - ), - child: _isEnrolled - ? _buildRequestFlow() - : _buildEnrollmentFlow(), - ), - ), - ), - ], - ), - if (_showConfirmation) _buildConfirmationModal(), - ], - ), - ); - } - - Widget _buildHeader() { - return Container( - padding: EdgeInsets.fromLTRB( - 20, - MediaQuery.of(context).padding.top + 20, - 20, - 32, - ), - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Color(0xFF0047FF), Color(0xFF0032A0)], - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () => context.go('/payments'), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 24, - ), - ), - const SizedBox(height: 16), - Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.zap, - color: Colors.white, - size: 24, - ), - ), - const SizedBox(width: 12), - const Text( - 'Early Pay', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - _isEnrolled - ? 'Get paid before payday' - : 'Access your earned wages instantly', - style: const TextStyle(color: Color(0xFFDBEAFE), fontSize: 14), - ), - ], - ), - ); - } - - Widget _buildEnrollmentFlow() { - if (_enrollmentStep == 'info') { - return Column( - children: [ - _buildInfoCard(), - const SizedBox(height: 16), - _buildFeeInfoCard(), - const SizedBox(height: 16), - _buildBenefitsCard(), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () => setState(() => _enrollmentStep = 'terms'), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - 'Continue to Terms', - style: TextStyle(fontWeight: FontWeight.w600), - ), - ), - ), - ], - ); - } else if (_enrollmentStep == 'terms') { - return Column( - children: [ - _buildTermsCard(), - const SizedBox(height: 16), - _buildTermsCheckbox(), - const SizedBox(height: 24), - Row( - children: [ - Expanded( - child: SizedBox( - height: 48, - child: OutlinedButton( - onPressed: () => setState(() => _enrollmentStep = 'info'), - style: OutlinedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text('Back'), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: SizedBox( - height: 48, - child: ElevatedButton( - onPressed: (_agreedToTerms && !_isLoading) - ? _handleEnroll - : null, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Text(_isLoading ? 'Enrolling...' : 'Enroll Now'), - ), - ), - ), - ], - ), - ], - ); - } else { - // Complete - return Column( - children: [ - Container( - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: Color(0xFFF0FDF4), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.checkCircle, - color: Color(0xFF16A34A), - size: 32, - ), - ), - const SizedBox(height: 16), - const Text( - 'You\'re All Set!', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 8), - const Text( - 'You can now access your earned wages anytime you need them.', - textAlign: TextAlign.center, - style: TextStyle(color: Color(0xFF475569)), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () { - setState(() { - _isEnrolled = true; - // Reset requests flow - _requestAmount = 0; - }); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - 'Continue to Early Pay', - style: TextStyle(fontWeight: FontWeight.w600), - ), - ), - ), - ], - ), - ), - ], - ); - } - } - - Widget _buildRequestFlow() { - return Column( - children: [ - // Available Amount Card - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - const Text( - 'Available for Early Pay', - style: TextStyle(color: Color(0xFF475569), fontSize: 14), - ), - const SizedBox(height: 4), - Text( - '\$${_availableAmount.toStringAsFixed(0)}', - style: const TextStyle( - fontSize: 36, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 4), - const Text( - 'Based on completed shifts', - style: TextStyle(color: Color(0xFF64748B), fontSize: 12), - ), - const SizedBox(height: 24), - - // Slider - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Request Amount', - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), - ), - Text( - '\$${_requestAmount.toStringAsFixed(0)}', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Color(0xFF0047FF), - ), - ), - ], - ), - const SizedBox(height: 8), - SliderTheme( - data: SliderTheme.of(context).copyWith( - trackHeight: 6, - activeTrackColor: const Color(0xFF0047FF), - inactiveTrackColor: const Color(0xFFE2E8F0), - thumbColor: Colors.white, - thumbShape: const RoundSliderThumbShape( - enabledThumbRadius: 10, - ), - overlayColor: const Color(0xFF0047FF).withOpacity(0.1), - ), - child: Slider( - value: _requestAmount, - min: 0, - max: _availableAmount, - divisions: (_availableAmount / 5).floor(), - onChanged: (val) => setState(() => _requestAmount = val), - ), - ), - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '\$0', - style: TextStyle(color: Color(0xFF64748B), fontSize: 12), - ), - Text( - '\$285', // Matches available amount - style: TextStyle(color: Color(0xFF64748B), fontSize: 12), - ), - ], - ), - - // Breakdown - if (_requestAmount > 0) ...[ - const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), - borderRadius: BorderRadius.circular(12), - ), - child: Column( - children: [ - _buildBreakdownRow( - 'Requested Amount', - '\$${_requestAmount.toStringAsFixed(2)}', - ), - const SizedBox(height: 8), - _buildBreakdownRow( - 'Service Fee (5%)', - '-\$${_serviceFee.toStringAsFixed(2)}', - isFee: true, - ), - const Divider(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'You Receive', - style: TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), - ), - ), - Text( - '\$${_netAmount.toStringAsFixed(2)}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - color: Color(0xFF0047FF), - ), - ), - ], - ), - ], - ), - ), - ], - - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: (_requestAmount > 0 && !_isLoading) - ? _handleRequest - : null, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Text( - _isLoading ? 'Processing...' : 'Request Early Pay', - ), - ), - ), - ], - ), - ), - - const SizedBox(height: 16), - _buildRequestInfoCard(), - ], - ); - } - - Widget _buildInfoCard() { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'How Early Pay Works', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 16), - _buildStep( - 1, - 'Work Your Shift', - 'Complete your scheduled shifts as normal', - ), - const SizedBox(height: 16), - _buildStep( - 2, - 'Request Early Pay', - 'Access up to 50% of earned wages before payday', - ), - const SizedBox(height: 16), - _buildStep( - 3, - 'Get Paid Instantly', - 'Funds transferred to your account within minutes', - ), - ], - ), - ); - } - - Widget _buildStep(int num, String title, String desc) { - return Row( - children: [ - Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Color(0xFFEFF6FF), - shape: BoxShape.circle, - ), - child: Center( - child: Text( - '$num', - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xFF2563EB), - ), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - Text( - desc, - style: const TextStyle(color: Color(0xFF475569), fontSize: 12), - ), - ], - ), - ), - ], - ); - } - - Widget _buildFeeInfoCard() { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: const Color(0xFFFFFBEB), - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon(LucideIcons.info, color: Color(0xFFD97706), size: 20), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text( - 'Service Fee', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - SizedBox(height: 4), - Text( - 'A 5% service fee applies to each Early Pay request. This fee covers the cost of instant transfer and processing.\n\nExample: Request \'100, receive \'95 (5% = \'5 fee)', - style: TextStyle(color: Color(0xFF475569), fontSize: 12), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildBenefitsCard() { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Key Benefits', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 12), - _buildCheckItem('No hidden fees or interest charges'), - const SizedBox(height: 8), - _buildCheckItem('Optional service - use only when you need it'), - const SizedBox(height: 8), - _buildCheckItem('Instant transfers to your bank account'), - const SizedBox(height: 8), - _buildCheckItem('No credit check or impact on credit score'), - ], - ), - ); - } - - Widget _buildCheckItem(String text) { - return Row( - children: [ - const Icon(LucideIcons.checkCircle, size: 16, color: Color(0xFF16A34A)), - const SizedBox(width: 8), - Text( - text, - style: const TextStyle(fontSize: 12, color: Color(0xFF475569)), - ), - ], - ); - } - - Widget _buildTermsCard() { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Terms & Conditions', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 16), - SizedBox( - height: 300, - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Early Pay Service Agreement', - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), - ), - const SizedBox(height: 8), - const Text( - 'By enrolling in Krow Early Pay, you agree to the following terms...', - style: TextStyle(fontSize: 12, color: Color(0xFF475569)), - ), - const SizedBox(height: 12), - _buildTermItem( - '1. Service Description', - 'Early Pay allows you to access up to 50% of your earned wages...', - ), - _buildTermItem( - '2. Fees and Charges', - 'A service fee of 5% will be deducted from each request...', - ), - _buildTermItem( - '3. Eligibility', - 'You must have completed at least one shift with verified hours...', - ), - _buildTermItem( - '4. Voluntary Participation', - 'Participation is optional...', - ), - // Add more if needed - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildTermItem(String title, String desc) { - return Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 13), - ), - Text( - desc, - style: const TextStyle(fontSize: 12, color: Color(0xFF475569)), - ), - ], - ), - ); - } - - Widget _buildTermsCheckbox() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: const Color(0xFFE2E8F0), width: 2), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 24, - height: 24, - child: Checkbox( - value: _agreedToTerms, - onChanged: (val) => setState(() => _agreedToTerms = val ?? false), - activeColor: const Color(0xFF0047FF), - ), - ), - const SizedBox(width: 12), - const Expanded( - child: Text( - 'I have read and agree to the Early Pay Terms & Conditions. I understand that a 5% service fee applies to each request and that participation is voluntary.', - style: TextStyle(fontSize: 12, color: Color(0xFF475569)), - ), - ), - ], - ), - ); - } - - Widget _buildBreakdownRow(String label, String value, {bool isFee = false}) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: const TextStyle(color: Color(0xFF475569), fontSize: 14), - ), - Text( - value, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: isFee ? const Color(0xFFD97706) : const Color(0xFF0F172A), - ), - ), - ], - ); - } - - Widget _buildRequestInfoCard() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), - borderRadius: BorderRadius.circular(16), - ), - child: Row( - children: [ - const Icon(LucideIcons.clock, color: Color(0xFF2563EB), size: 20), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Instant Transfer', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: Color(0xFF0F172A), - ), - ), - Text( - 'Funds are typically transferred to your account within minutes of approval.', - style: TextStyle(color: Color(0xFF475569), fontSize: 12), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildConfirmationModal() { - return GestureDetector( - onTap: () => setState(() => _showConfirmation = false), - child: Container( - color: Colors.black.withOpacity(0.5), - child: Center( - child: GestureDetector( - onTap: () {}, // consume tap - child: Container( - margin: const EdgeInsets.all(20), - padding: const EdgeInsets.all(24), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: Color(0xFFF0FDF4), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.checkCircle, - color: Color(0xFF16A34A), - size: 32, - ), - ), - const SizedBox(height: 16), - const Text( - 'Transfer Initiated!', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const SizedBox(height: 8), - Text( - '\$${_netAmount.toStringAsFixed(2)} is being transferred to your account. You should see it within minutes.', - textAlign: TextAlign.center, - style: const TextStyle(color: Color(0xFF475569)), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () { - context.go('/payments'); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text('Back to Earnings'), - ), - ), - ], - ), - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/earnings_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/earnings_screen.dart deleted file mode 100644 index 9563598c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/earnings_screen.dart +++ /dev/null @@ -1,667 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class EarningsScreen extends StatefulWidget { - const EarningsScreen({super.key}); - - @override - State createState() => _EarningsScreenState(); -} - -class _EarningsScreenState extends State { - String _period = 'week'; - - // Mock Data - final double _totalEarnings = 12450.75; - final double _weeklyEarnings = 412.00; - final double _monthlyEarnings = 1650.50; - final double _pendingEarnings = 285.50; - - final List> _recentPayments = [ - {'date': 'Dec 15', 'amount': 285.50, 'shifts': 3, 'status': 'PAID'}, - {'date': 'Dec 8', 'amount': 412.00, 'shifts': 4, 'status': 'PAID'}, - {'date': 'Dec 1', 'amount': 198.75, 'shifts': 2, 'status': 'PAID'}, - ]; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - body: SingleChildScrollView( - padding: const EdgeInsets.only(bottom: 24), - child: Column( - children: [ - _buildHeader(), - Transform.translate( - offset: const Offset(0, -20), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - _buildQuickStats(), - const SizedBox(height: 20), - _buildPendingEarnings(), - const SizedBox(height: 20), - _buildActions(), - const SizedBox(height: 20), - _buildPaymentHistory(), - const SizedBox(height: 20), - _buildSavingsGoal(), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader() { - return Container( - padding: const EdgeInsets.only(top: 60, left: 20, right: 20, bottom: 40), - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFF059669), - Color(0xFF0F766E), - ], // emerald-600 to teal-700 - ), - ), - child: Column( - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Earnings', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 24), - const Text( - 'Total Earnings', - style: TextStyle( - color: Color(0xFFA7F3D0), // emerald-200 - fontSize: 14, - ), - ), - const SizedBox(height: 4), - Text( - '\$${_totalEarnings.toStringAsFixed(2)}', - style: const TextStyle( - color: Colors.white, - fontSize: 36, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - _buildTab('week', 'Week'), - _buildTab('month', 'Month'), - _buildTab('year', 'Year'), - ], - ), - ), - ], - ), - ); - } - - Widget _buildTab(String value, String label) { - final isSelected = _period == value; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _period = value), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(8), - ), - child: Text( - label, - textAlign: TextAlign.center, - style: TextStyle( - color: isSelected ? const Color(0xFF047857) : Colors.white, - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - ), - ), - ); - } - - Widget _buildQuickStats() { - return Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: const Color(0xFFD1FAE5), // emerald-100 - borderRadius: BorderRadius.circular(8), - ), - child: const Icon( - LucideIcons.trendingUp, - size: 16, - color: Color(0xFF059669), - ), - ), - const SizedBox(width: 8), - const Text( - 'This Week', - style: TextStyle( - color: AppColors.krowMuted, - fontSize: 12, - ), - ), - ], - ), - const SizedBox(height: 12), - Text( - '\$${_weeklyEarnings.toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: const Color(0xFFDBEAFE), // blue-100 - borderRadius: BorderRadius.circular(8), - ), - child: const Icon( - LucideIcons.calendar, - size: 16, - color: Color(0xFF2563EB), - ), - ), - const SizedBox(width: 8), - const Text( - 'This Month', - style: TextStyle( - color: AppColors.krowMuted, - fontSize: 12, - ), - ), - ], - ), - const SizedBox(height: 12), - Text( - '\$${_monthlyEarnings.toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ), - ), - ], - ); - } - - Widget _buildPendingEarnings() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - Color(0xFFFFFBEB), - Color(0xFFFEFCE8), - ], // amber-50 to yellow-50 - ), - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: const Color(0xFFFEF3C7), // amber-100 - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.wallet, - color: Color(0xFFD97706), - size: 24, - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Pending Payout', - style: TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - Text( - '\$${_pendingEarnings.toStringAsFixed(2)}', - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ], - ), - ElevatedButton( - onPressed: () { - // Navigate to early pay screen - context.push('/early-pay'); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.transparent, - padding: EdgeInsets.zero, - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - Color(0xFFF59E0B), - Color(0xFFF97316), - ], // amber-500 to orange-500 - ), - borderRadius: BorderRadius.circular(12), - ), - child: const Row( - children: [ - Icon(LucideIcons.zap, size: 16, color: Colors.white), - SizedBox(width: 4), - Text( - 'Instant Pay', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14, - ), - ), - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildActions() { - return Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () { - // Navigate to tax forms screen - context.push('/tax-forms'); - }, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 16), - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - backgroundColor: Colors.white, - ), - child: const Column( - children: [ - Icon( - LucideIcons.fileText, - color: AppColors.krowMuted, - size: 20, - ), - SizedBox(height: 8), - Text( - 'Tax Documents', - style: TextStyle(color: AppColors.krowCharcoal, fontSize: 14), - ), - ], - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: OutlinedButton( - onPressed: () {}, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 16), - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - backgroundColor: Colors.white, - ), - child: const Column( - children: [ - Icon( - LucideIcons.download, - color: AppColors.krowMuted, - size: 20, - ), - SizedBox(height: 8), - Text( - 'Export Report', - style: TextStyle(color: AppColors.krowCharcoal, fontSize: 14), - ), - ], - ), - ), - ), - ], - ); - } - - Widget _buildPaymentHistory() { - return Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Payment History', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - GestureDetector( - onTap: () {}, // Navigate to full history - child: const Row( - children: [ - Text( - 'View all', - style: TextStyle( - color: Color(0xFF7C3AED), // violet-600 - fontWeight: FontWeight.w500, - fontSize: 14, - ), - ), - Icon( - LucideIcons.chevronRight, - size: 16, - color: Color(0xFF7C3AED), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - ..._recentPayments.map( - (payment) => Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Color(0xFFD1FAE5), // emerald-100 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.dollarSign, - color: Color(0xFF059669), - size: 20, - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '\$${payment['amount'].toStringAsFixed(2)}', - style: const TextStyle( - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - Text( - '${payment['shifts']} shifts • ${payment['date']}', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: const Color(0xFFD1FAE5), // emerald-100 - borderRadius: BorderRadius.circular(12), - ), - child: const Text( - 'PAID', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF047857), - ), - ), - ), - ], - ), - ), - ), - ), - ], - ); - } - - Widget _buildSavingsGoal() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - Color(0xFFF5F3FF), - Color(0xFFFAF5FF), - ], // violet-50 to purple-50 - ), - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Savings Goal', - style: TextStyle( - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - TextButton( - onPressed: () {}, - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - child: const Text( - 'Edit', - style: TextStyle(color: Color(0xFF7C3AED)), // violet-600 - ), - ), - ], - ), - const SizedBox(height: 12), - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Emergency Fund', - style: TextStyle(fontSize: 14, color: AppColors.krowMuted), - ), - Text( - '\$850 / \$1,000', - style: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const SizedBox(height: 8), - Container( - height: 8, - width: double.infinity, - decoration: BoxDecoration( - color: const Color(0xFFEDE9FE), // violet-100 - borderRadius: BorderRadius.circular(4), - ), - child: FractionallySizedBox( - alignment: Alignment.centerLeft, - widthFactor: 0.85, - child: Container( - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - Color(0xFF8B5CF6), - Color(0xFFA855F7), - ], // violet-500 to purple-500 - ), - borderRadius: BorderRadius.circular(4), - ), - ), - ), - ), - const SizedBox(height: 8), - const Text( - '🎯 \$150 to go! Keep it up!', - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/jobs_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/jobs_screen.dart deleted file mode 100644 index 9eab049d..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/jobs_screen.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -import '../../theme.dart'; -import '../../services/mock_service.dart'; -import '../../models/shift.dart'; -import '../../widgets/shift_card.dart'; - -class JobsScreen extends ConsumerStatefulWidget { - const JobsScreen({super.key}); - - @override - ConsumerState createState() => _JobsScreenState(); -} - -class _JobsScreenState extends ConsumerState { - String _searchQuery = ''; - late Future> _jobsFuture; - - // Filter state - - @override - void initState() { - super.initState(); - _jobsFuture = mockService.getRecommendedShifts(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - body: SafeArea( - child: Column( - children: [ - _buildHeader(), - Expanded( - child: FutureBuilder>( - future: _jobsFuture, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } - - if (snapshot.hasError) { - return Center(child: Text('Error: ${snapshot.error}')); - } - - final allShifts = snapshot.data ?? []; - - // Simple Mock Filtering - final filteredShifts = allShifts.where((shift) { - // Search - if (_searchQuery.isNotEmpty) { - final q = _searchQuery.toLowerCase(); - if (!shift.title.toLowerCase().contains(q) && - !shift.clientName.toLowerCase().contains(q)) { - return false; - } - } - - return true; - }).toList(); - - return Column( - children: [ - // Results Count - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - child: Row( - children: [ - Text( - '${filteredShifts.length}', - style: const TextStyle( - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - ' shifts available', - style: TextStyle(color: AppColors.krowMuted), - ), - ], - ), - ), - - // List - Expanded( - child: filteredShifts.isEmpty - ? _buildEmptyState() - : ListView.builder( - padding: const EdgeInsets.symmetric( - horizontal: 20, - ), - itemCount: filteredShifts.length, - - itemBuilder: (context, index) { - final shift = filteredShifts[index]; - return ShiftCard( - shift: shift, - compact: true, - disableTapNavigation: true, // Disable navigation for Jobs screen - ); - }, - ), - ), - ], - ); - }, - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader() { - return Container( - color: Colors.white.withOpacity(0.8), - padding: const EdgeInsets.fromLTRB(20, 16, 20, 0), - child: Column( - children: [ - Row( - children: [ - GestureDetector( - onTap: () => - context.go('/worker-home'), // Use go to return to shell - child: Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Color(0xFFF1F5F9), // slate-100 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: AppColors.krowMuted, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Find Shifts', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const SizedBox(height: 16), - - // Search - Container( - height: 48, - decoration: BoxDecoration( - color: AppColors.krowYellow.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBlue.withOpacity(0.1)), - ), - child: TextField( - onChanged: (val) => setState(() => _searchQuery = val), - decoration: const InputDecoration( - prefixIcon: Icon( - LucideIcons.search, - color: AppColors.krowMuted, - ), - hintText: 'Search by role, location...', - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 12), - ), - ), - ), - const SizedBox(height: 16), - ], - ), - ); - } - - Widget _buildEmptyState() { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.search, - size: 32, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 16), - const Text( - 'No shifts found', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const SizedBox(height: 4), - const Text( - 'Try adjusting your filters', - style: TextStyle(color: AppColors.krowMuted), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/payments_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/payments_screen.dart deleted file mode 100644 index e91863c4..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/payments_screen.dart +++ /dev/null @@ -1,272 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../widgets/payments/payment_stats_card.dart'; -import '../../widgets/payments/pending_pay_card.dart'; -import '../../widgets/payments/payment_history_item.dart'; - -class PaymentsScreen extends StatefulWidget { - const PaymentsScreen({super.key}); - - @override - State createState() => _PaymentsScreenState(); -} - -class _PaymentsScreenState extends State { - String _period = 'week'; - - // Mock data matching React - final double _weeklyEarnings = 847.50; - final double _monthlyEarnings = 3240; - final double _pendingEarnings = 285; - final double _totalEarnings = 12450; - - final List> _recentPayments = [ - { - 'date': 'Sat, Dec 6', - 'title': 'Cook', - 'location': 'LA Convention Center', - 'address': '1201 S Figueroa St, Los Angeles, CA 90015', - 'workedTime': '2:00 PM - 10:00 PM', - 'amount': 160.00, - 'status': 'PAID', - 'hours': 8, - 'rate': 20, - }, - { - 'date': 'Fri, Dec 5', - 'title': 'Server', - 'location': 'The Grand Hotel', - 'address': '456 Main St, Los Angeles, CA 90012', - 'workedTime': '5:00 PM - 11:00 PM', - 'amount': 176.00, - 'status': 'PAID', - 'hours': 8, - 'rate': 22, - }, - { - 'date': 'Thu, Dec 4', - 'title': 'Bartender', - 'location': 'Club Luxe', - 'address': '789 Sunset Blvd, Los Angeles, CA 90028', - 'workedTime': '6:00 PM - 2:00 AM', - 'amount': 225.00, - 'status': 'PAID', - 'hours': 9, - 'rate': 25, - }, - ]; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), // slate-50 matches React - body: SingleChildScrollView( - child: Column( - children: [ - // Header Section with Gradient - Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF0032A0), Color(0xFF333F48)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - padding: EdgeInsets.fromLTRB( - 20, - MediaQuery.of(context).padding.top + 24, - 20, - 32, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Earnings", - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - const SizedBox(height: 24), - - // Main Balance - Center( - child: Column( - children: [ - const Text( - "Total Earnings", - style: TextStyle( - color: Color(0xFFF8E08E), - fontSize: 14, - ), - ), - const SizedBox(height: 4), - Text( - "\$${_totalEarnings.toStringAsFixed(0).replaceAllMapped(RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},')}", - style: const TextStyle( - fontSize: 36, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - const SizedBox(height: 16), - - // Period Tabs - Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - _buildTab("Week", 'week'), - _buildTab("Month", 'month'), - _buildTab("Year", 'year'), - ], - ), - ), - ], - ), - ), - - // Main Content - Offset upwards - Transform.translate( - offset: const Offset(0, -16), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Quick Stats - Row( - children: [ - Expanded( - child: PaymentStatsCard( - icon: LucideIcons.trendingUp, - iconColor: const Color(0xFF059669), - label: "This Week", - amount: "\$${_weeklyEarnings}", // React shows 847.5 - ), - ), - const SizedBox(width: 12), - Expanded( - child: PaymentStatsCard( - icon: LucideIcons.calendar, - iconColor: const Color(0xFF2563EB), - label: "This Month", - amount: "\$${_monthlyEarnings.toStringAsFixed(0)}", - ), - ), - ], - ), - const SizedBox(height: 16), - - // Pending Pay - PendingPayCard( - amount: _pendingEarnings, - onCashOut: () { - context.push('/early-pay'); - }, - ), - const SizedBox(height: 24), - - // Recent Payments - const Text( - "Recent Payments", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 12), - Column( - children: _recentPayments.asMap().entries.map((entry) { - final payment = entry.value; - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: PaymentHistoryItem( - amount: (payment['amount'] as num).toDouble(), - title: payment['title'], - location: payment['location'], - address: payment['address'], - date: payment['date'], - workedTime: payment['workedTime'], - hours: payment['hours'], - rate: (payment['rate'] as num).toDouble(), - status: payment['status'], - ), - ); - }).toList(), - ), - const SizedBox(height: 16), - - // Export History Button - SizedBox( - width: double.infinity, - height: 48, - child: OutlinedButton.icon( - onPressed: () { - // Show snackbar with "PDF Exported" message - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('PDF Exported'), - duration: Duration(seconds: 2), - ), - ); - }, - icon: const Icon(LucideIcons.download, size: 16), - label: const Text("Export History"), - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF0F172A), - side: const BorderSide(color: Color(0xFFE2E8F0)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ), - const SizedBox(height: 32), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildTab(String label, String value) { - final isSelected = _period == value; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _period = value), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Text( - label, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isSelected ? const Color(0xFF0032A0) : Colors.white, - ), - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/shift_details_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/shift_details_screen.dart deleted file mode 100644 index 93544cc4..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/shift_details_screen.dart +++ /dev/null @@ -1,809 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../theme.dart'; -import '../../models/shift.dart'; - -class ShiftDetailsScreen extends StatefulWidget { - final String shiftId; - final Shift? shift; // Optional: pass shift object directly if available - - const ShiftDetailsScreen({super.key, required this.shiftId, this.shift}); - - @override - State createState() => _ShiftDetailsScreenState(); -} - -class _ShiftDetailsScreenState extends State { - late Shift _shift; - bool _isLoading = true; - bool _showDetails = true; - bool _isApplying = false; - - // Mock Managers - final List> _managers = [ - {'name': 'John Smith', 'phone': '+1 123 456 7890'}, - {'name': 'Jane Doe', 'phone': '+1 123 456 7890'}, - ]; - - @override - void initState() { - super.initState(); - _loadShift(); - } - - void _loadShift() async { - if (widget.shift != null) { - _shift = widget.shift!; - setState(() => _isLoading = false); - } else { - // Simulate fetch - await Future.delayed(const Duration(milliseconds: 500)); - // Fallback mock if not passed - if (mounted) { - setState(() { - _shift = Shift( - id: widget.shiftId, - title: 'Event Server', - clientName: 'Grand Hotel', - logoUrl: null, - hourlyRate: 25.0, - date: DateFormat('yyyy-MM-dd').format(DateTime.now()), - startTime: '16:00', - endTime: '22:00', - location: 'Downtown', - locationAddress: '123 Main St, New York, NY', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: - 'Provide exceptional customer service. Respond to guest requests or concerns promptly and professionally.', - managers: [], - ); - _isLoading = false; - }); - } - } - } - - String _formatTime(String time) { - if (time.isEmpty) return ''; - try { - final parts = time.split(':'); - final hour = int.parse(parts[0]); - final minute = int.parse(parts[1]); - final dt = DateTime(2022, 1, 1, hour, minute); - return DateFormat('h:mma').format(dt).toLowerCase(); - } catch (e) { - return time; - } - } - - String _formatDate(String dateStr) { - if (dateStr.isEmpty) return ''; - try { - final date = DateTime.parse(dateStr); - return DateFormat('MMMM d').format(date); - } catch (e) { - return dateStr; - } - } - - double _calculateHours(String start, String end) { - try { - final startParts = start.split(':').map(int.parse).toList(); - final endParts = end.split(':').map(int.parse).toList(); - double h = - (endParts[0] - startParts[0]) + (endParts[1] - startParts[1]) / 60; - if (h < 0) h += 24; - return h; - } catch (e) { - return 0; - } - } - - @override - Widget build(BuildContext context) { - if (_isLoading) { - return const Scaffold( - backgroundColor: AppColors.krowBackground, - body: Center(child: CircularProgressIndicator()), - ); - } - - final hours = _calculateHours(_shift.startTime, _shift.endTime); - final totalPay = _shift.hourlyRate * hours; - - return Scaffold( - backgroundColor: AppColors.krowBackground, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: AppColors.krowMuted), - onPressed: () => context.pop(), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: AppColors.krowBorder, height: 1.0), - ), - ), - body: Stack( - children: [ - SingleChildScrollView( - padding: const EdgeInsets.fromLTRB(20, 20, 20, 120), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Pending Badge (Mock logic) - Align( - alignment: Alignment.centerRight, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 4, - ), - decoration: BoxDecoration( - color: AppColors.krowYellow.withOpacity(0.3), - borderRadius: BorderRadius.circular(20), - ), - child: const Text( - 'Pending 6h ago', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ), - ), - const SizedBox(height: 16), - - // Header - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 56, - height: 56, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: _shift.logoUrl != null - ? ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Image.network( - _shift.logoUrl!, - fit: BoxFit.contain, - ), - ) - : Center( - child: Text( - _shift.clientName[0], - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - _shift.title, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '\$${_shift.hourlyRate.toStringAsFixed(0)}/h', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - '(exp.total \$${totalPay.toStringAsFixed(0)})', - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - Text( - _shift.clientName, - style: const TextStyle(color: AppColors.krowMuted), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 16), - - // Tags - Row( - children: [ - _buildTag( - LucideIcons.zap, - 'Immediate start', - AppColors.krowBlue.withOpacity(0.1), - AppColors.krowBlue, - ), - const SizedBox(width: 8), - _buildTag( - LucideIcons.star, - 'No experience', - AppColors.krowYellow.withOpacity(0.3), - AppColors.krowCharcoal, - ), - ], - ), - const SizedBox(height: 24), - - // Additional Details - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - InkWell( - onTap: () => - setState(() => _showDetails = !_showDetails), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'ADDITIONAL DETAILS', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - letterSpacing: 0.5, - color: AppColors.krowMuted, - ), - ), - Icon( - _showDetails - ? LucideIcons.chevronUp - : LucideIcons.chevronDown, - color: AppColors.krowMuted, - size: 20, - ), - ], - ), - ), - ), - if (_showDetails) - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), - child: Column( - children: [ - _buildDetailRow('Tips', 'Yes', true), - _buildDetailRow('Travel Time', 'Yes', true), - _buildDetailRow('Meal Provided', 'No', false), - _buildDetailRow('Parking Available', 'Yes', true), - _buildDetailRow('Gas Compensation', 'No', false), - ], - ), - ), - ], - ), - ), - const SizedBox(height: 16), - - // Date & Duration Grid - Row( - children: [ - Expanded( - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'START', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 8), - Text( - _formatDate(_shift.date), - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'Date', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 12), - Text( - _formatTime(_shift.startTime), - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'Time', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - ), - const SizedBox(width: 16), - Expanded( - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'DURATION', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 8), - Text( - '${hours.toStringAsFixed(0)} hours', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'Shift duration', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 12), - const Text( - '1 hour', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const Text( - 'Break duration', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - ), - ], - ), - const SizedBox(height: 16), - - // Location - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'LOCATION', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 12), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _shift.location, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - _shift.locationAddress, - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - OutlinedButton.icon( - onPressed: () { - // Show snackbar with the address - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - _shift.locationAddress ?? _shift.location, - ), - duration: const Duration(seconds: 3), - ), - ); - }, - icon: const Icon(LucideIcons.navigation, size: 14), - label: const Text('Get direction'), - style: OutlinedButton.styleFrom( - foregroundColor: AppColors.krowCharcoal, - side: const BorderSide( - color: AppColors.krowBorder, - ), - textStyle: const TextStyle(fontSize: 12), - ), - ), - ], - ), - const SizedBox(height: 16), - Container( - height: 160, - width: double.infinity, - decoration: BoxDecoration( - color: const Color(0xFFF1F3F5), - borderRadius: BorderRadius.circular(12), - ), - child: const Center( - child: Icon( - LucideIcons.map, - color: AppColors.krowMuted, - size: 48, - ), - ), - ), - ], - ), - ), - const SizedBox(height: 16), - - // Manager Contact - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'MANAGER CONTACT DETAILS', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 16), - ..._managers - .map( - (manager) => Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [ - AppColors.krowBlue, - Color(0xFF0830B8), - ], - ), - borderRadius: BorderRadius.circular( - 8, - ), - ), - child: const Center( - child: Icon( - LucideIcons.user, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - manager['name']!, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - Text( - manager['phone']!, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - OutlinedButton.icon( - onPressed: () { - // Show snackbar with the phone number - ScaffoldMessenger.of( - context, - ).showSnackBar( - SnackBar( - content: Text(manager['phone']!), - duration: const Duration(seconds: 3), - ), - ); - }, - icon: const Icon( - LucideIcons.phone, - size: 14, - color: Color(0xFF059669), - ), - label: const Text( - 'Call', - style: TextStyle( - color: Color(0xFF059669), - ), - ), - style: OutlinedButton.styleFrom( - side: const BorderSide( - color: Color(0xFFA7F3D0), - ), - backgroundColor: const Color(0xFFECFDF5), - textStyle: const TextStyle(fontSize: 12), - ), - ), - ], - ), - ), - ) - .toList(), - ], - ), - ), - const SizedBox(height: 16), - - // Additional Info - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'ADDITIONAL INFO', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - ), - ), - const SizedBox(height: 12), - Text( - _shift.description ?? - 'Providing Exceptional Customer Service.', - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - height: 1.5, - ), - ), - ], - ), - ), - ], - ), - ), - - // Bottom Actions - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowBorder)), - ), - child: SafeArea( - top: false, - child: Column( - children: [ - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () async { - setState(() => _isApplying = true); - await Future.delayed(const Duration(seconds: 1)); - if (mounted) { - setState(() => _isApplying = false); - context.pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Shift Accepted!'), - backgroundColor: Color(0xFF10B981), - ), - ); - } - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: _isApplying - ? const SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator( - color: Colors.white, - ), - ) - : const Text( - 'Accept shift', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - ), - ), - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - height: 48, - child: TextButton( - onPressed: () => context.pop(), - child: const Text( - 'Decline shift', - style: TextStyle( - color: Color(0xFFEF4444), - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - ), - ), - ], - ), - ), - ), - ), - ], - ), - ); - } - - Widget _buildTag(IconData icon, String label, Color bg, Color text) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - children: [ - Icon(icon, size: 14, color: text), - const SizedBox(width: 4), - Text( - label, - style: TextStyle( - color: text, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ); - } - - Widget _buildDetailRow(String label, String value, bool isPositive) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 6), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: const TextStyle(fontSize: 14, color: AppColors.krowMuted), - ), - Text( - value, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isPositive ? const Color(0xFF059669) : AppColors.krowMuted, - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/shifts_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/shifts_screen.dart deleted file mode 100644 index c46bfa5f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/shifts_screen.dart +++ /dev/null @@ -1,1268 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../theme.dart'; -import '../../models/shift.dart'; -import '../../widgets/shifts/my_shift_card.dart'; -import '../../widgets/shifts/shift_assignment_card.dart'; - -class ShiftsScreen extends StatefulWidget { - final String? initialTab; - const ShiftsScreen({super.key, this.initialTab}); - - @override - State createState() => _ShiftsScreenState(); -} - -class _ShiftsScreenState extends State { - late String _activeTab; - String _searchQuery = ''; - // ignore: unused_field - String? _cancelledShiftDemo; // 'lastMinute' or 'advance' - String _jobType = 'all'; // all, one-day, multi-day, long-term - - // Calendar State - DateTime _selectedDate = DateTime.now(); - int _weekOffset = 0; - - @override - void initState() { - super.initState(); - _activeTab = widget.initialTab ?? 'myshifts'; - } - - @override - void didUpdateWidget(ShiftsScreen oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.initialTab != null && widget.initialTab != _activeTab) { - setState(() { - _activeTab = widget.initialTab!; - }); - } - } - - // Mock Data - final List _pendingAssignments = [ - Shift( - id: 'p1', - title: 'Event Server', - clientName: 'Grand Hotel', - logoUrl: null, - hourlyRate: 25.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 2))), - startTime: '16:00', - endTime: '22:00', - location: 'Downtown', - locationAddress: '123 Main St', - status: 'pending', - createdDate: DateTime.now().toIso8601String(), - ), - ]; - - final List _myShifts = [ - Shift( - id: 'm1', - title: 'Warehouse Assistant', - clientName: 'Amazon', - logoUrl: - 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/Amazon_2024.svg/500px-Amazon_2024.svg.png', - hourlyRate: 22.5, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 1))), - startTime: '09:00', - endTime: '17:00', - location: 'Logistics Park', - locationAddress: '456 Industrial Way', - status: 'confirmed', - createdDate: DateTime.now().toIso8601String(), - description: 'Standard warehouse duties. Safety boots required.', - ), - ]; - - final List _availableJobs = [ - Shift( - id: 'a1', - title: 'Bartender', - clientName: 'Club Luxe', - logoUrl: null, - hourlyRate: 30.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 3))), - startTime: '20:00', - endTime: '02:00', - location: 'City Center', - locationAddress: '789 Nightlife Blvd', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'Experience mixing cocktails required.', - ), - Shift( - id: 'a2', - title: 'Line Cook (Multi-Day)', - clientName: 'Bistro Roma', - logoUrl: null, - hourlyRate: 24.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 4))), - startTime: '15:00', - endTime: '23:00', - location: 'Little Italy', - locationAddress: '321 Pasta Ln', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'Italian cuisine experience preferred. 3-day event.', - durationDays: 3, - ), - Shift( - id: 'a3', - title: 'Warehouse Manager (Long Term)', - clientName: 'Logistics Co', - logoUrl: null, - hourlyRate: 35.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 1))), - startTime: '08:00', - endTime: '17:00', - location: 'Port Area', - locationAddress: '100 Dock St', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'Long term supervisory role.', - ), - Shift( - id: 'a4', - title: 'Event Server', - clientName: 'Grand Hotel', - logoUrl: null, - hourlyRate: 22.0, - date: DateFormat('yyyy-MM-dd').format(DateTime.now()), - startTime: '18:00', - endTime: '23:00', - location: 'Downtown', - locationAddress: '456 Main St', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'Wedding reception service. Black tie attire required.', - ), - Shift( - id: 'a5', - title: 'Retail Associate (Multi-Day)', - clientName: 'Fashion Outlet', - logoUrl: null, - hourlyRate: 18.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 2))), - startTime: '10:00', - endTime: '18:00', - location: 'Shopping Mall', - locationAddress: '200 Retail Plaza', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'Weekend sale event. Customer service experience needed.', - durationDays: 2, - ), - Shift( - id: 'a6', - title: 'Construction Helper', - clientName: 'BuildCo', - logoUrl: null, - hourlyRate: 28.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 1))), - startTime: '07:00', - endTime: '15:00', - location: 'North District', - locationAddress: '789 Construction Site', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'General labor. Safety equipment provided.', - ), - Shift( - id: 'a7', - title: 'Office Administrator (Long Term)', - clientName: 'Tech Startup', - logoUrl: null, - hourlyRate: 32.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 7))), - startTime: '09:00', - endTime: '17:00', - location: 'Tech Hub', - locationAddress: '500 Innovation Dr', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: - '6-month contract position. Office management experience required.', - ), - Shift( - id: 'a8', - title: 'Delivery Driver', - clientName: 'QuickShip', - logoUrl: null, - hourlyRate: 25.0, - date: DateFormat('yyyy-MM-dd').format(DateTime.now()), - startTime: '12:00', - endTime: '20:00', - location: 'Citywide', - locationAddress: '100 Logistics Center', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: 'Valid driver license required. Own vehicle preferred.', - ), - Shift( - id: 'a9', - title: 'Conference Staff (Multi-Day)', - clientName: 'TechCon 2024', - logoUrl: null, - hourlyRate: 26.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 5))), - startTime: '08:00', - endTime: '18:00', - location: 'Convention Center', - locationAddress: '300 Conference Dr', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: '4-day tech conference. Registration and attendee support.', - durationDays: 4, - ), - Shift( - id: 'a10', - title: 'Festival Vendor (Multi-Day)', - clientName: 'Summer Music Fest', - logoUrl: null, - hourlyRate: 20.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().add(const Duration(days: 10))), - startTime: '11:00', - endTime: '23:00', - location: 'City Park', - locationAddress: '400 Park Ave', - status: 'open', - createdDate: DateTime.now().toIso8601String(), - description: '5-day music festival. Food and beverage service.', - durationDays: 5, - ), - ]; - - final List _historyShifts = [ - Shift( - id: 'h1', - title: 'Event Staff', - clientName: 'Convention Center', - logoUrl: null, - hourlyRate: 20.0, - date: DateFormat( - 'yyyy-MM-dd', - ).format(DateTime.now().subtract(const Duration(days: 5))), - startTime: '08:00', - endTime: '16:00', - location: 'South Hall', - locationAddress: '555 Exhibit Dr', - status: 'completed', - createdDate: DateTime.now() - .subtract(const Duration(days: 10)) - .toIso8601String(), - ), - ]; - - List _getCalendarDays() { - final now = DateTime.now(); - // In Dart, weekday is 1(Mon)..7(Sun). - // React logic: currentDay is 0(Sun)..6(Sat). - // React: daysSinceFriday = (currentDay + 2) % 7. - // Let's map Dart weekday to React day index: - // Mon(1)->1, Tue(2)->2, ..., Sat(6)->6, Sun(7)->0. - int reactDayIndex = now.weekday == 7 ? 0 : now.weekday; - int daysSinceFriday = (reactDayIndex + 2) % 7; - - // Start date is now - daysSinceFriday + (weekOffset * 7) - final start = now - .subtract(Duration(days: daysSinceFriday)) - .add(Duration(days: _weekOffset * 7)); - // Reset to midnight - final startDate = DateTime(start.year, start.month, start.day); - - return List.generate(7, (index) => startDate.add(Duration(days: index))); - } - - bool _isSameDay(DateTime a, DateTime b) { - return a.year == b.year && a.month == b.month && a.day == b.day; - } - - void _confirmShift(String id) { - setState(() { - final index = _pendingAssignments.indexWhere((shift) => shift.id == id); - if (index != -1) { - final confirmedShift = _pendingAssignments.removeAt(index); - // In a real app, this would be added to _myShifts with status 'confirmed' - // For now, just remove from pending and show snackbar - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Shift ${confirmedShift.title} confirmed! (Placeholder)'), - duration: const Duration(seconds: 2), - ), - ); - } - }); - } - - void _declineShift(String id) { - setState(() { - final index = _pendingAssignments.indexWhere((shift) => shift.id == id); - if (index != -1) { - final declinedShift = _pendingAssignments.removeAt(index); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Shift ${declinedShift.title} declined. (Placeholder)'), - duration: const Duration(seconds: 2), - ), - ); - } - }); - } - - @override - Widget build(BuildContext context) { - // Filter available jobs based on search and job type - final filteredJobs = _availableJobs.where((s) { - final matchesSearch = - s.title.toLowerCase().contains(_searchQuery.toLowerCase()) || - s.location.toLowerCase().contains(_searchQuery.toLowerCase()) || - s.clientName.toLowerCase().contains(_searchQuery.toLowerCase()); - - if (!matchesSearch) return false; - - if (_jobType == 'all') return true; - if (_jobType == 'one-day') { - // Mock: Consider anything without "Long Term" in title as one day for demo - return !s.title.contains('Long Term') && !s.title.contains('Multi-Day'); - } - if (_jobType == 'multi-day') { - return s.title.contains('Multi-Day'); - } - if (_jobType == 'long-term') { - return s.title.contains('Long Term'); - } - return true; - }).toList(); - - // Calculate dates for current week view - final calendarDays = _getCalendarDays(); - final weekStartDate = calendarDays.first; - final weekEndDate = calendarDays.last; - - // Filter my shifts by week - final visibleMyShifts = _myShifts.where((s) { - final sDateStr = s.date; - final wStartStr = DateFormat('yyyy-MM-dd').format(weekStartDate); - final wEndStr = DateFormat('yyyy-MM-dd').format(weekEndDate); - return sDateStr.compareTo(wStartStr) >= 0 && - sDateStr.compareTo(wEndStr) <= 0; - }).toList(); - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - // Header - Container( - color: AppColors.krowBlue, - padding: EdgeInsets.fromLTRB( - 20, - MediaQuery.of(context).padding.top + 20, - 20, - 24, // React: pb-6 (24px) - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - "Shifts", - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - // Demo Buttons - Row( - children: [ - _buildDemoButton( - "Demo: Cancel <4hr", - const Color(0xFFEF4444), - () { - setState(() => _cancelledShiftDemo = 'lastMinute'); - _showCancelledModal('lastMinute'); - }, - ), - const SizedBox(width: 8), - _buildDemoButton( - "Demo: Cancel >4hr", - const Color(0xFFF59E0B), - () { - setState(() => _cancelledShiftDemo = 'advance'); - _showCancelledModal('advance'); - }, - ), - ], - ), - ], - ), - const SizedBox(height: 16), - - // Tabs - Row( - children: [ - _buildTab( - "myshifts", - "My Shifts", - LucideIcons.calendar, - _myShifts.length, - ), - const SizedBox(width: 8), - _buildTab( - "find", - "Find Shifts", - LucideIcons.search, - filteredJobs.length, - ), - const SizedBox(width: 8), - _buildTab( - "history", - "History", - LucideIcons.clock, - _historyShifts.length, - ), - ], - ), - ], - ), - ), - - // Calendar Selector (Only for My Shifts) - if (_activeTab == 'myshifts') - Container( - color: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20), - child: Column( - children: [ - // Month/Year Header - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - InkWell( - onTap: () => setState(() => _weekOffset--), - borderRadius: BorderRadius.circular(20), - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Icon( - LucideIcons.chevronLeft, - size: 20, - color: AppColors.krowCharcoal, - ), - ), - ), - Text( - DateFormat('MMMM yyyy').format(weekStartDate), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - InkWell( - onTap: () => setState(() => _weekOffset++), - borderRadius: BorderRadius.circular(20), - child: const Padding( - padding: EdgeInsets.all(8.0), - child: Icon( - LucideIcons.chevronRight, - size: 20, - color: AppColors.krowCharcoal, - ), - ), - ), - ], - ), - ), - // Days Grid - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: calendarDays.map((date) { - final isSelected = _isSameDay(date, _selectedDate); - final dateStr = DateFormat('yyyy-MM-dd').format(date); - final hasShifts = _myShifts.any((s) => s.date == dateStr); - - return GestureDetector( - onTap: () => setState(() => _selectedDate = date), - child: Container( - width: 44, // roughly grid cols 7 - padding: const EdgeInsets.symmetric(vertical: 12), - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue - : Colors.white, - borderRadius: BorderRadius.circular( - 999, - ), // full rounded - border: Border.all( - color: isSelected - ? AppColors.krowBlue - : AppColors.krowBorder, - width: 1, - ), - ), - child: Column( - children: [ - Text( - date.day.toString().padLeft(2, '0'), - style: TextStyle( - fontSize: 20, // text-xl - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 2), - Text( - DateFormat('E').format(date), // short weekday - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: isSelected - ? Colors.white.withOpacity(0.8) - : AppColors.krowMuted, - ), - ), - if (hasShifts) - Container( - margin: const EdgeInsets.only(top: 4), - width: 6, - height: 6, - decoration: BoxDecoration( - color: isSelected - ? Colors.white - : AppColors.krowBlue, - shape: BoxShape.circle, - ), - ), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - - if (_activeTab == 'myshifts') - const Divider(height: 1, color: AppColors.krowBorder), - - // Body - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - // Search Bar & Job Type Filter (Find Work Only) - if (_activeTab == 'find') ...[ - // Search Bar - Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Container( - height: 48, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: TextField( - onChanged: (val) => - setState(() => _searchQuery = val), - decoration: const InputDecoration( - prefixIcon: Icon( - LucideIcons.search, - size: 20, - color: AppColors.krowMuted, - ), - border: InputBorder.none, - hintText: "Search jobs...", - hintStyle: TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - contentPadding: EdgeInsets.symmetric(vertical: 12), - ), - ), - ), - ), - - // Job Type Filter Tabs (React-style equal width) - Container( - margin: const EdgeInsets.only(bottom: 16), - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: const Color(0xFFF1F3F5), - borderRadius: BorderRadius.circular(999), - ), - child: Row( - children: [ - _buildFilterTab('all', 'All Jobs'), - _buildFilterTab('one-day', 'One Day'), - _buildFilterTab('multi-day', 'Multi-Day'), - _buildFilterTab('long-term', 'Long Term'), - ], - ), - ), - ], - // Content Stacks - if (_activeTab == 'myshifts') ...[ - // Pending Assignments - if (_pendingAssignments.isNotEmpty) ...[ - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - children: [ - Container( - width: 8, - height: 8, - decoration: const BoxDecoration( - color: Color(0xFFF59E0B), // amber-500 - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - const Text( - "Awaiting Confirmation", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFFD97706), // amber-600 - ), - ), - ], - ), - ), - ), - ..._pendingAssignments.map( - (shift) => Padding( - padding: const EdgeInsets.only(bottom: 16), - child: ShiftAssignmentCard( - shift: shift, - onConfirm: () => _confirmShift(shift.id), - onDecline: () => _declineShift(shift.id), - ), - ), - ), - ], - - // Cancelled Shift Demo (Static List as per React) - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(bottom: 12), - child: const Text( - "Cancelled Shifts", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowMuted, - ), - ), - ), - ), - // Card 1: Cancelled <4hr - _buildCancelledCard( - title: "Annual Tech Conference", - client: "TechCorp Inc.", - pay: "\$200", - rate: "\$25/hr · 8h", - date: "Today", - time: "10:00 AM - 6:00 PM", - address: "123 Convention Center Dr, San Jose, CA", - isLastMinute: true, - onTap: () => - setState(() => _cancelledShiftDemo = 'lastMinute'), - ), - const SizedBox(height: 12), - // Card 2: Cancelled >4hr - _buildCancelledCard( - title: "Morning Catering Setup", - client: "EventPro Services", - pay: "\$120", - rate: "\$20/hr · 6h", - date: "Tomorrow", - time: "8:00 AM - 2:00 PM", - address: "456 Grand Ballroom Ave, San Francisco, CA", - isLastMinute: false, - onTap: () => - setState(() => _cancelledShiftDemo = 'advance'), - ), - const SizedBox(height: 24), - - // Confirmed Shifts - if (visibleMyShifts.isEmpty && - _pendingAssignments.isEmpty) ...[ - // Empty State - _buildEmptyState( - LucideIcons.calendar, - "No upcoming shifts", - "Find work to get started", - "Find Work", - () => setState(() => _activeTab = 'find'), - ), - ] else if (visibleMyShifts.isNotEmpty) ...[ - // Header only if other sections exist - if (_pendingAssignments.isNotEmpty) - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(bottom: 12), - child: const Text( - "Confirmed Shifts", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowMuted, - ), - ), - ), - ), - ...visibleMyShifts.map( - (shift) => MyShiftCard( - shift: shift, - onDecline: () {}, - onRequestSwap: () {}, - ), - ), - ], - ], - - if (_activeTab == 'find') ...[ - if (filteredJobs.isEmpty) - _buildEmptyState( - LucideIcons.search, - "No jobs available", - "Check back later", - null, - null, - ) - else - ...filteredJobs.map( - (shift) => MyShiftCard( - shift: shift, - onAccept: () {}, - onDecline: () {}, - ), - ), - ], - - if (_activeTab == 'history') ...[ - if (_historyShifts.isEmpty) - _buildEmptyState( - LucideIcons.clock, - "No shift history", - "Completed shifts appear here", - null, - null, - ) - else - ..._historyShifts.map( - (shift) => MyShiftCard(shift: shift, historyMode: true), - ), - ], - ], - ), - ), - ), - ], - ), - ); - } - - Widget _buildFilterTab(String id, String label) { - final isSelected = _jobType == id; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _jobType = id), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - decoration: BoxDecoration( - color: isSelected ? AppColors.krowBlue : Colors.transparent, - borderRadius: BorderRadius.circular(999), - boxShadow: isSelected - ? [ - BoxShadow( - color: AppColors.krowBlue.withOpacity(0.2), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ] - : null, - ), - child: Text( - label, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 11, - fontWeight: FontWeight.w600, - color: isSelected ? Colors.white : AppColors.krowMuted, - ), - ), - ), - ), - ); - } - - Widget _buildTab(String id, String label, IconData icon, int count) { - final isActive = _activeTab == id; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _activeTab = id), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8), - decoration: BoxDecoration( - color: isActive - ? Colors.white - : Colors.white.withAlpha((0.2 * 255).round()), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - icon, - size: 14, - color: isActive ? AppColors.krowBlue : Colors.white, - ), - const SizedBox(width: 6), - Flexible( - child: Text( - label, - style: TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - color: isActive ? AppColors.krowBlue : Colors.white, - ), - overflow: TextOverflow.ellipsis, - ), - ), - const SizedBox(width: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - constraints: const BoxConstraints(minWidth: 18), - decoration: BoxDecoration( - color: isActive - ? AppColors.krowBlue.withAlpha((0.1 * 255).round()) - : Colors.white.withAlpha((0.2 * 255).round()), - borderRadius: BorderRadius.circular(999), - ), - child: Center( - child: Text( - "$count", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: isActive ? AppColors.krowBlue : Colors.white, - ), - ), - ), - ), - ], - ), - ), - ), - ); - } - - Widget _buildDemoButton(String label, Color color, VoidCallback onTap) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - label, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ); - } - - Widget _buildEmptyState( - IconData icon, - String title, - String subtitle, - String? actionLabel, - VoidCallback? onAction, - ) { - return Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 64), - child: Column( - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: const Color(0xFFF1F3F5), - borderRadius: BorderRadius.circular(12), - ), - child: Icon(icon, size: 32, color: AppColors.krowMuted), - ), - const SizedBox(height: 16), - Text( - title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 4), - Text( - subtitle, - style: const TextStyle(fontSize: 14, color: AppColors.krowMuted), - ), - if (actionLabel != null && onAction != null) ...[ - const SizedBox(height: 16), - ElevatedButton( - onPressed: onAction, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: Text(actionLabel), - ), - ], - ], - ), - ), - ); - } - - Widget _buildCancelledCard({ - required String title, - required String client, - required String pay, - required String rate, - required String date, - required String time, - required String address, - required bool isLastMinute, - required VoidCallback onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - width: 6, - height: 6, - decoration: const BoxDecoration( - color: Color(0xFFEF4444), - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 6), - const Text( - "CANCELLED", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Color(0xFFEF4444), - ), - ), - if (isLastMinute) ...[ - const SizedBox(width: 4), - const Text( - "• 4hr compensation", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: Color(0xFF10B981), - ), - ), - ], - ], - ), - const SizedBox(height: 12), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 44, - height: 44, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - AppColors.krowBlue.withAlpha((0.15 * 255).round()), - AppColors.krowBlue.withAlpha((0.08 * 255).round()), - ], - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: AppColors.krowBlue.withAlpha((0.15 * 255).round()), - ), - ), - child: const Center( - child: Icon( - LucideIcons.briefcase, - color: AppColors.krowBlue, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - Text( - client, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - pay, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - rate, - style: const TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - date, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 12), - const Icon( - LucideIcons.clock, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - time, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - const SizedBox(height: 4), - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Expanded( - child: Text( - address, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ], - ), - ), - ], - ), - ], - ), - ), - ); - } - - void _showCancelledModal(String type) { - final isLastMinute = type == 'lastMinute'; - showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), - title: Row( - children: [ - const Icon(LucideIcons.xCircle, color: Color(0xFFEF4444)), - const SizedBox(width: 8), - const Text("Shift Cancelled"), - ], - ), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "We're sorry, but the following shift has been cancelled by the client:", - style: TextStyle(fontSize: 14), - ), - const SizedBox(height: 12), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.grey.shade50, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.grey.shade200), - ), - child: const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Annual Tech Conference", - style: TextStyle(fontWeight: FontWeight.bold), - ), - Text("Today, 10:00 AM - 6:00 PM"), - ], - ), - ), - const SizedBox(height: 16), - if (isLastMinute) - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: const Color(0xFFECFDF5), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFF10B981)), - ), - child: const Row( - children: [ - Icon( - LucideIcons.checkCircle, - color: Color(0xFF10B981), - size: 16, - ), - SizedBox(width: 8), - Expanded( - child: Text( - "You are eligible for 4hr cancellation compensation.", - style: TextStyle( - fontSize: 12, - color: Color(0xFF065F46), - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ), - ) - else - const Text( - "Reduced schedule at the venue. No compensation is due as this was cancelled more than 4 hours in advance.", - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: const Text("Close"), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_home_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_home_screen.dart deleted file mode 100644 index c9c30170..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_home_screen.dart +++ /dev/null @@ -1,825 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../theme.dart'; -import '../../widgets/shift_card.dart'; -import '../../widgets/worker/auto_match_toggle.dart'; -import '../../widgets/worker/benefits_widget.dart'; -import '../../widgets/worker/improve_yourself_widget.dart'; -import '../../widgets/worker/more_ways_widget.dart'; -import '../../services/mock_service.dart'; -import '../../models/shift.dart'; - -class WorkerHomeScreen extends ConsumerStatefulWidget { - const WorkerHomeScreen({super.key}); - - @override - ConsumerState createState() => _WorkerHomeScreenState(); -} - -class _WorkerHomeScreenState extends ConsumerState { - late Future> _todayShiftsFuture; - late Future> _tomorrowShiftsFuture; - late Future> _recommendedShiftsFuture; - bool _autoMatchEnabled = false; - bool _isProfileComplete = false; // Added for mock profile completion - - @override - void initState() { - super.initState(); - _todayShiftsFuture = mockService.getTodayShifts(); - _tomorrowShiftsFuture = mockService.getTomorrowShifts(); - _recommendedShiftsFuture = mockService.getRecommendedShifts(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: SafeArea( - child: SingleChildScrollView( - padding: const EdgeInsets.only(bottom: 100), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildHeader(), - - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - if (!_isProfileComplete) - _buildPlaceholderBanner( - "Complete Your Profile", - "Get verified to see more shifts", - Colors.blue[50]!, - Colors.blue, - onTap: () { - context.push('/worker-profile'); - }, - ), - const SizedBox(height: 20), - _buildPlaceholderBanner( - "Availability", - "Update your availability for next week", - Colors.orange[50]!, - Colors.orange, - onTap: () => context.push('/availability'), - ), - const SizedBox(height: 20), - - // Auto Match Toggle - AutoMatchToggle( - enabled: _autoMatchEnabled, - onToggle: (val) => - setState(() => _autoMatchEnabled = val), - ), - const SizedBox(height: 20), - - // Quick Actions - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: _buildQuickAction( - context, - LucideIcons.search, - "Find Shifts", - () => context.go('/shifts'), - ), - ), - Expanded( - child: _buildQuickAction( - context, - LucideIcons.calendar, - "Availability", - () => context.push('/availability'), - ), - ), - Expanded( - child: _buildQuickAction( - context, - LucideIcons.messageSquare, - "Messages", - () => context.push('/messages'), - ), - ), - Expanded( - child: _buildQuickAction( - context, - LucideIcons.dollarSign, - "Earnings", - () => context.go('/payments'), - ), - ), - ], - ), - const SizedBox(height: 24), - - // Today's Shifts - FutureBuilder>( - future: _todayShiftsFuture, - builder: (context, snapshot) { - final shifts = snapshot.data ?? []; - return Column( - children: [ - _buildSectionHeader( - "Today's Shift", - shifts.isNotEmpty - ? "${shifts.length} scheduled" - : null, - ), - if (shifts.isEmpty) - _buildEmptyState( - "No shifts scheduled for today", - "Find shifts →", - () => context.go('/shifts?tab=find'), - ) - else - Column( - children: shifts - .map( - (shift) => ShiftCard( - shift: shift, - compact: true, - ), - ) - .toList(), - ), - ], - ); - }, - ), - const SizedBox(height: 24), - - // Tomorrow's Shifts - FutureBuilder>( - future: _tomorrowShiftsFuture, - builder: (context, snapshot) { - final shifts = snapshot.data ?? []; - return Column( - children: [ - _buildSectionHeader("Tomorrow", null), - if (shifts.isEmpty) - _buildEmptyState("No shifts for tomorrow", null) - else - Column( - children: shifts - .map( - (shift) => ShiftCard( - shift: shift, - compact: true, - ), - ) - .toList(), - ), - ], - ); - }, - ), - const SizedBox(height: 24), - - // Pending Payment Card - _buildPendingPaymentCard(), - const SizedBox(height: 24), - - // Recommended Shifts - _buildSectionHeader("Recommended for You", "View all"), - FutureBuilder>( - future: _recommendedShiftsFuture, - builder: (context, snapshot) { - if (!snapshot.hasData || snapshot.data!.isEmpty) { - return _buildEmptyState( - "No recommended shifts", - null, - ); - } - return SizedBox( - height: 160, // Adjusted height for horizontal list - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: snapshot.data!.length, - clipBehavior: Clip.none, // Allow shadows to paint - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(right: 12), - child: _buildRecommendedCard( - snapshot.data![index], - ), - ); - }, - ), - ); - }, - ), - const SizedBox(height: 24), - - // Benefits Widget - const BenefitsWidget(), - const SizedBox(height: 24), - - // Improve Yourself - const ImproveYourselfWidget(), - const SizedBox(height: 24), - - // More Ways To Use Krow - const MoreWaysToUseKrowWidget(), - ], - ), - ), - ], - ), - ), - ), - ); - } - - Widget _buildSectionHeader(String title, String? action) { - return Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, // semibold - color: AppColors.krowCharcoal, - ), - ), - if (action != null) - if (action == "View all") - GestureDetector( - onTap: () => context.go('/shifts?tab=find'), - child: const Row( - children: [ - Text( - "View all", - style: TextStyle( - color: AppColors.krowBlue, - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), - Icon( - LucideIcons.chevronRight, - size: 16, - color: AppColors.krowBlue, - ), - ], - ), - ) - else - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: AppColors.krowBlue.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: AppColors.krowBlue.withValues(alpha: 0.2), - ), - ), - child: Text( - action, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: AppColors.krowBlue, - ), - ), - ), - ], - ), - ); - } - - Widget _buildEmptyState( - String message, - String? actionLink, [ - VoidCallback? onAction, - ]) { - return Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFF1F3F5), // secondary - borderRadius: BorderRadius.circular(8), // rounded-lg - ), - alignment: Alignment.center, - child: Column( - children: [ - Text( - message, - style: const TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - if (actionLink != null) - GestureDetector( - onTap: onAction, - child: Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - actionLink, - style: const TextStyle( - color: AppColors.krowBlue, - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), - ), - ), - ], - ), - ); - } - - Widget _buildHeader() { - return Padding( - padding: const EdgeInsets.fromLTRB(20, 24, 20, 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: AppColors.krowBlue.withValues(alpha: 0.2), - width: 2, - ), - ), - child: CircleAvatar( - backgroundColor: AppColors.krowBlue.withValues(alpha: 0.1), - child: const Text( - 'K', - style: TextStyle( - color: AppColors.krowBlue, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Welcome back', - style: TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - Text( - 'Krower', - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ], - ), - Row( - children: [ - GestureDetector( - onTap: () => context.push('/messages'), - child: Stack( - children: [ - _buildHeaderIcon(LucideIcons.bell), - const Positioned( - top: -2, - right: -2, - child: CircleAvatar( - radius: 8, - backgroundColor: Color(0xFFF04444), - child: Text( - '2', - style: TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), - ), - const SizedBox(width: 8), - GestureDetector( - onTap: () => context.go('/worker-profile'), - child: _buildHeaderIcon(LucideIcons.settings), - ), - ], - ), - ], - ), - ); - } - - Widget _buildHeaderIcon(IconData icon) { - return Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Icon(icon, color: AppColors.krowMuted, size: 20), - ); - } - - Widget _buildPlaceholderBanner( - String title, - String subtitle, - Color bg, - Color accent, { - VoidCallback? onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: accent.withValues(alpha: 0.3)), - ), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: const BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: Icon(LucideIcons.star, color: accent, size: 20), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - subtitle, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - Icon(LucideIcons.chevronRight, color: accent), - ], - ), - ), - ); - } - - Widget _buildQuickAction( - BuildContext context, - IconData icon, - String label, - VoidCallback onTap, - ) { - return GestureDetector( - onTap: onTap, - child: Column( - children: [ - Container( - width: 50, - height: 50, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFF1F5F9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Icon(icon, color: AppColors.krowBlue, size: 24), - ), - const SizedBox(height: 8), - Text( - label, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } - - Widget _buildPendingPaymentCard() { - return GestureDetector( - onTap: () => context.go('/payments'), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [Colors.blue[50]!.withValues(alpha: 0.5), Colors.blue[50]!], - begin: Alignment.centerLeft, - end: Alignment.centerRight, - ), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.blue[100]!.withValues(alpha: 0.5)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Row( - children: [ - Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Color(0xFFE8F0FF), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.dollarSign, - color: Color(0xFF0047FF), - size: 20, - ), - ), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Pending Payment", - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: AppColors.krowCharcoal, - ), - overflow: TextOverflow.ellipsis, - ), - Text( - "Payment processing", - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - ], - ), - ), - const Row( - children: [ - Text( - "\$285.00", - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - color: Color(0xFF0047FF), - ), - ), - SizedBox(width: 8), - Icon( - LucideIcons.chevronRight, - color: Color(0xFF94A3B8), - size: 20, - ), - ], - ), - ], - ), - ), - ); - } - - Widget _buildRecommendedCard(Shift shift) { - // Basic calculation for total pay - final duration = 8; // Simplified duration - final totalPay = duration * shift.hourlyRate; - - return GestureDetector( - onTap: () { - // Apply for the shift (matching React's applyMutation logic) - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Applied for ${shift.title}'), - backgroundColor: Colors.green, - duration: const Duration(seconds: 2), - ), - ); - }, - child: Container( - width: 300, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.02), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - // Badges - Row( - children: [ - const Text( - "• ACT NOW", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Color(0xFFDC2626), // red-600 - ), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 2, - ), - decoration: BoxDecoration( - color: const Color(0xFFE8F0FF), - borderRadius: BorderRadius.circular(999), - ), - child: const Text( - "One Day", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: Color(0xFF0047FF), - ), - ), - ), - ], - ), - const SizedBox(height: 12), - // Content - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 44, - height: 44, - decoration: BoxDecoration( - color: const Color(0xFFE8F0FF), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.calendar, - color: Color(0xFF0047FF), - size: 20, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - shift.title, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: AppColors.krowCharcoal, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - Text( - "\$${totalPay.round()}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const SizedBox(height: 2), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - shift.clientName, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - Text( - "\$${shift.hourlyRate.toStringAsFixed(0)}/hr • ${duration}h", - style: const TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - // Footer Info - Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - "Today", // Mock - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 12), - const Icon( - LucideIcons.clock, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - "${shift.startTime} - ${shift.endTime}", - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - const SizedBox(height: 4), - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Expanded( - child: Text( - shift.locationAddress ?? shift.location, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/certificates_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/certificates_screen.dart deleted file mode 100644 index 6350b7bd..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/certificates_screen.dart +++ /dev/null @@ -1,908 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import '../../../../theme.dart'; - -class CertificatesScreen extends ConsumerStatefulWidget { - const CertificatesScreen({super.key}); - - @override - ConsumerState createState() => _CertificatesScreenState(); -} - -class _CertificatesScreenState extends ConsumerState { - // Mock Data - final List> _certificates = [ - { - 'id': 'background', - 'name': 'Background Check', - 'icon': LucideIcons.fileCheck, - 'color': const Color(0xFF0A39DF), - 'description': 'Required for all shifts', - 'status': 'COMPLETED', - 'expiry': DateTime.now().add(const Duration(days: 365)).toIso8601String(), - }, - { - 'id': 'food_handler', - 'name': 'Food Handler', - 'icon': LucideIcons.utensils, - 'color': const Color(0xFF0A39DF), - 'description': 'Required for food service', - 'status': 'EXPIRING', // within 30 days - 'expiry': DateTime.now().add(const Duration(days: 15)).toIso8601String(), - }, - { - 'id': 'rbs', - 'name': 'RBS Alcohol', - 'icon': LucideIcons.wine, - 'color': const Color(0xFF121826), - 'description': 'Required for bar shifts', - 'status': 'NOT_STARTED', - 'expiry': null, - }, - ]; - - @override - Widget build(BuildContext context) { - final int completedCount = _certificates - .where((c) => c['status'] == 'COMPLETED') - .length; - final int totalCount = _certificates.length; - final int progress = (completedCount / totalCount * 100).round(); - - return Scaffold( - backgroundColor: const Color(0xFFF8FAFC), - body: SingleChildScrollView( - child: Column( - children: [ - _buildHeader(progress, completedCount, totalCount), - Transform.translate( - offset: const Offset(0, -48), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - ..._certificates.map(_buildCertificateCard), - const SizedBox(height: 16), - _buildAddMoreCard(), - const SizedBox(height: 32), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader(int progress, int completedCount, int totalCount) { - return Container( - padding: const EdgeInsets.fromLTRB(20, 60, 20, 80), - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Color(0xFF0A39DF), Color(0xFF1E40AF)], - ), - ), - child: Column( - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.chevronLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'Certificates', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 32), - Row( - children: [ - SizedBox( - width: 96, - height: 96, - child: Stack( - fit: StackFit.expand, - children: [ - CircularProgressIndicator( - value: progress / 100, - strokeWidth: 8, - backgroundColor: Colors.white.withOpacity(0.2), - valueColor: const AlwaysStoppedAnimation( - Color(0xFFF9E547), - ), - ), - Center( - child: Text( - '$progress%', - style: const TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ), - const SizedBox(width: 24), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Your Progress', - style: TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 4), - Text( - '$completedCount of $totalCount verified', - style: TextStyle( - color: Colors.white.withOpacity(0.7), - fontSize: 14, - ), - ), - const SizedBox(height: 8), - const Row( - children: [ - Icon( - LucideIcons.shield, - color: Color(0xFFF9E547), - size: 16, - ), - SizedBox(width: 8), - Text( - 'Compliance Active', - style: TextStyle( - color: Color(0xFFF9E547), - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ], - ), - ], - ), - ], - ), - ); - } - - Widget _buildCertificateCard(Map cert) { - final String status = cert['status']; - final bool isExpiring = status == 'EXPIRING'; - final bool isComplete = status == 'COMPLETED'; - final bool isPending = status == 'PENDING'; - final bool isNotStarted = status == 'NOT_STARTED'; - - DateTime? expiryDate; - if (cert['expiry'] != null) { - expiryDate = DateTime.parse(cert['expiry']); - } - - int daysUntilExpiry = 0; - if (expiryDate != null) { - daysUntilExpiry = expiryDate.difference(DateTime.now()).inDays; - } - - return Container( - margin: const EdgeInsets.only(bottom: 16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - clipBehavior: Clip.hardEdge, - child: Column( - children: [ - if (isExpiring) - Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - decoration: BoxDecoration( - color: const Color(0xFFF9E547).withOpacity(0.2), - border: const Border( - bottom: BorderSide(color: Color(0x66F9E547)), - ), - ), - child: Row( - children: [ - const Icon( - LucideIcons.alertTriangle, - size: 16, - color: Color(0xFF121826), - ), - const SizedBox(width: 8), - Text( - daysUntilExpiry > 0 - ? 'Expires in $daysUntilExpiry days - Renew now' - : 'Expired - Renew now', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ], - ), - ), - - Padding( - padding: const EdgeInsets.all(20), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: cert['color'].withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - ), - child: Center( - child: Icon( - cert['icon'], - color: cert['color'], - size: 28, - ), - ), - ), - if (isComplete) - const Positioned( - bottom: -4, - right: -4, - child: CircleAvatar( - radius: 12, - backgroundColor: Color(0xFF0A39DF), - child: Icon( - LucideIcons.checkCircle, - color: Colors.white, - size: 16, - ), - ), - ), - if (isPending) - const Positioned( - bottom: -4, - right: -4, - child: CircleAvatar( - radius: 12, - backgroundColor: Color(0xFF121826), - child: Icon( - LucideIcons.clock, - color: Colors.white, - size: 16, - ), - ), - ), - ], - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - cert['name'], - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 2), - Text( - cert['description'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - ], - ), - const Icon( - LucideIcons.chevronRight, - color: Color(0xFF6A7382), - size: 20, - ), - ], - ), - const SizedBox(height: 16), - - if (isComplete) _buildCompleteStatus(expiryDate), - - if (isExpiring) _buildExpiringStatus(expiryDate), - - if (isNotStarted) - SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: () => _showUploadModal(context, cert), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0A39DF), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.symmetric(vertical: 12), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - LucideIcons.upload, - size: 16, - color: Colors.white, - ), - SizedBox(width: 8), - Text( - 'Upload Certificate', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Colors.white, - ), - ), - ], - ), - ), - ), - - // Edit and Remove buttons for completed/expiring certificates - if (isComplete || isExpiring) ...[ - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - child: OutlinedButton.icon( - onPressed: () => _showEditExpiryDialog(cert), - icon: const Icon(LucideIcons.pencil, size: 16), - label: const Text('Edit Expiration Date'), - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF121826), - side: const BorderSide(color: Color(0xFFE3E6E9)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.symmetric(vertical: 12), - ), - ), - ), - const SizedBox(height: 8), - SizedBox( - width: double.infinity, - child: TextButton.icon( - onPressed: () => _showRemoveConfirmation(cert), - icon: const Icon(LucideIcons.trash2, size: 16), - label: const Text('Remove Certificate'), - style: TextButton.styleFrom( - foregroundColor: Colors.red, - padding: const EdgeInsets.symmetric(vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ), - ], - ], - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildCompleteStatus(DateTime? expiryDate) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 8, - height: 8, - decoration: const BoxDecoration( - color: Color(0xFF0A39DF), - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - const Text( - 'Verified', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF0A39DF), - fontSize: 14, - ), - ), - ], - ), - if (expiryDate != null) - Text( - 'Exp: ${DateFormat('MMM d, yyyy').format(expiryDate)}', - style: const TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ); - } - - Widget _buildExpiringStatus(DateTime? expiryDate) { - return Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - width: 8, - height: 8, - decoration: const BoxDecoration( - color: Color(0xFF0A39DF), - shape: BoxShape.circle, - ), - ), // Assuming blinking not essential for MVP Flutter - const SizedBox(width: 8), - const Text( - 'Expiring Soon', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF0A39DF), - fontSize: 14, - ), - ), - ], - ), - if (expiryDate != null) - Padding( - padding: const EdgeInsets.only(top: 4), - child: Text( - 'Exp: ${DateFormat('MMM d, yyyy').format(expiryDate)}', - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - ), - ], - ), - Row( - children: [ - _buildIconButton(LucideIcons.eye, () { - // Show snackbar indicating certificate opened - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Certificate opened in new tab'), - duration: Duration(seconds: 2), - ), - ); - }), - const SizedBox(width: 8), - _buildSmallOutlineButton( - 'Renew', - () => _showUploadModal(context, null), - ), // Passing null just to open generic upload for now or handle logic - ], - ), - ], - ); - } - - Widget _buildIconButton(IconData icon, VoidCallback onTap) { - return InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(16), - child: Container( - width: 32, - height: 32, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.transparent, - border: Border.all( - color: Colors.transparent, - ), // Placeholder for consistent sizing - ), - child: const Center( - child: Icon(LucideIcons.eye, size: 16, color: Color(0xFF6A7382)), - ), - ), - ); - } - - Widget _buildSmallOutlineButton(String label, VoidCallback onTap) { - return OutlinedButton( - onPressed: onTap, - style: OutlinedButton.styleFrom( - side: const BorderSide(color: Color(0x660A39DF)), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0), - minimumSize: const Size(0, 32), - ), - child: Text( - label, - style: const TextStyle(fontSize: 12, color: Color(0xFF0A39DF)), - ), - ); - } - - Widget _buildAddMoreCard() { - return GestureDetector( - onTap: () => _showUploadModal(context, null), - child: Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Colors.grey[50]!, Colors.grey[100]!], - ), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: Colors.grey[300]!, - style: BorderStyle.solid, - ), // Dashed border needs custom painter, solid fine for MVP - ), - child: const Row( - children: [ - Icon(LucideIcons.plus, color: Color(0xFF0A39DF), size: 24), - SizedBox(width: 16), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Add Another Certificate', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: Color(0xFF121826), - ), - ), - SizedBox(height: 2), - Text( - 'Boost your profile with more credentials', - style: TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ), - ], - ), - ), - ); - } - - void _showUploadModal(BuildContext context, Map? cert) { - showModalBottomSheet( - context: context, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (context) => Container( - height: MediaQuery.of(context).size.height * 0.85, - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical(top: Radius.circular(32)), - ), - child: Column( - children: [ - // Header - Container( - height: 128, - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color(0xFF0A39DF), Color(0xFF1E40AF)], - ), - borderRadius: BorderRadius.vertical(top: Radius.circular(32)), - ), - child: Stack( - alignment: Alignment.center, - clipBehavior: Clip.none, - children: [ - Positioned( - top: 16, - right: 16, - child: IconButton( - icon: const Icon(LucideIcons.x, color: Colors.white), - onPressed: () => context.pop(), - ), - ), - Positioned( - bottom: -32, - child: Container( - width: 80, - height: 80, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 10, - ), - ], - ), - child: Center( - child: Icon( - cert != null ? cert['icon'] : LucideIcons.fileCheck, - size: 40, - color: const Color(0xFF0A39DF), - ), - ), - ), - ), - ], - ), - ), - const SizedBox(height: 48), - Text( - cert != null ? cert['name'] : 'New Certificate', - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 24), - // Upload Options - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Row( - children: [ - Expanded( - child: _buildUploadOption(LucideIcons.camera, 'Take Photo'), - ), - const SizedBox(width: 16), - Expanded( - child: _buildUploadOption( - LucideIcons.upload, - 'Upload File', - ), - ), - ], - ), - ), - const SizedBox(height: 16), - const Text( - 'Supported formats: PDF, JPG, PNG (max 10MB)', - style: TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ), - ), - ); - } - - Widget _buildUploadOption(IconData icon, String label) { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), - borderRadius: BorderRadius.circular(16), - ), - child: Column( - children: [ - Container( - width: 56, - height: 56, - decoration: const BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: Center(child: Icon(icon, color: const Color(0xFF0A39DF))), - ), - const SizedBox(height: 12), - Text( - label, - style: const TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ], - ), - ); - } - - // Edit Expiry Date Dialog - Future _showEditExpiryDialog(Map cert) async { - DateTime? currentExpiry; - if (cert['expiry'] != null) { - currentExpiry = DateTime.parse(cert['expiry']); - } - - DateTime selectedDate = currentExpiry ?? DateTime.now(); - - await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Row( - children: [ - Icon(LucideIcons.calendar, size: 20, color: AppColors.krowBlue), - const SizedBox(width: 8), - const Text( - 'Update Expiration Date', - style: TextStyle(fontSize: 18), - ), - ], - ), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Expiration Date', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 12), - InkWell( - onTap: () async { - final DateTime? picked = await showDatePicker( - context: context, - initialDate: selectedDate, - firstDate: DateTime.now(), - lastDate: DateTime.now().add(const Duration(days: 3650)), - ); - if (picked != null) { - selectedDate = picked; - } - }, - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - border: Border.all(color: const Color(0xFFE3E6E9)), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - DateFormat('MMM d, yyyy').format(selectedDate), - style: const TextStyle(fontSize: 16), - ), - const Icon(LucideIcons.calendar, size: 20), - ], - ), - ), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () { - // Update the certificate expiry date - setState(() { - final index = _certificates.indexWhere( - (c) => c['id'] == cert['id'], - ); - if (index != -1) { - _certificates[index]['expiry'] = selectedDate - .toIso8601String(); - // Update status based on new expiry - final daysUntilExpiry = selectedDate - .difference(DateTime.now()) - .inDays; - if (daysUntilExpiry <= 30) { - _certificates[index]['status'] = 'EXPIRING'; - } else { - _certificates[index]['status'] = 'COMPLETED'; - } - } - }); - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Expiration date updated successfully'), - backgroundColor: Colors.green, - ), - ); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - ), - child: const Text('Save'), - ), - ], - ); - }, - ); - } - - // Remove Certificate Confirmation Dialog - Future _showRemoveConfirmation(Map cert) async { - final bool? confirmed = await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Remove Certificate'), - content: Text( - 'Are you sure you want to remove "${cert['name']}"? This action cannot be undone.', - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: const Text('Cancel'), - ), - ElevatedButton( - onPressed: () => Navigator.of(context).pop(true), - style: ElevatedButton.styleFrom( - backgroundColor: Colors.red, - foregroundColor: Colors.white, - ), - child: const Text('Remove'), - ), - ], - ); - }, - ); - - if (confirmed == true) { - setState(() { - _certificates.removeWhere((c) => c['id'] == cert['id']); - }); - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('${cert['name']} removed successfully'), - backgroundColor: Colors.red, - ), - ); - } - } - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/documents_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/documents_screen.dart deleted file mode 100644 index 7f31eeb2..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/documents_screen.dart +++ /dev/null @@ -1,296 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class DocumentsScreen extends ConsumerStatefulWidget { - const DocumentsScreen({super.key}); - - @override - ConsumerState createState() => _DocumentsScreenState(); -} - -class _DocumentsScreenState extends ConsumerState { - // Mock Data - final List> _requiredDocs = [ - { - 'userId': 'id', - 'name': 'Government ID', - 'description': 'Passport, Driver\'s License, or State ID', - 'status': 'VERIFIED', - }, - { - 'userId': 'ssn', - 'name': 'Social Security Card', - 'description': 'Or W-9 Form', - 'status': 'PENDING', - }, - { - 'userId': 'work_auth', - 'name': 'Work Authorization', - 'description': 'I-9 or Work Permit', - 'status': 'VERIFIED', - }, - { - 'userId': 'address', - 'name': 'Proof of Address', - 'description': 'Utility bill or bank statement', - 'status': 'MISSING', - }, - ]; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Documents', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - children: [ - _buildProgressCard(), - const SizedBox(height: 16), - _buildDocumentsList(), - ], - ), - ), - ); - } - - Widget _buildProgressCard() { - final completedCount = _requiredDocs - .where((d) => d['status'] == 'VERIFIED') - .length; - final totalCount = _requiredDocs.length; - final progress = totalCount > 0 ? completedCount / totalCount : 0.0; - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Document Verification', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - Text( - '$completedCount/$totalCount Complete', - style: const TextStyle(fontSize: 14, color: Color(0xFF0A39DF)), - ), - ], - ), - const SizedBox(height: 8), - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: LinearProgressIndicator( - value: progress, - minHeight: 8, - backgroundColor: const Color(0xFFE3E6E9), - valueColor: const AlwaysStoppedAnimation( - Color(0xFF0A39DF), - ), - ), - ), - ], - ), - ); - } - - Widget _buildDocumentsList() { - return Column( - children: _requiredDocs.map((doc) => _buildDocumentCard(doc)).toList(), - ); - } - - Widget _buildDocumentCard(Map doc) { - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: const Color(0xFF0A39DF).withOpacity(0.1), - borderRadius: BorderRadius.circular(8), - ), - child: const Center( - child: Icon( - LucideIcons.fileText, - color: Color(0xFF0A39DF), - size: 20, - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - doc['name'], - style: const TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - _getStatusIcon(doc['status']), - ], - ), - const SizedBox(height: 2), - Text( - doc['description'], - style: const TextStyle( - fontSize: 14, - color: Color(0xFF6A7382), - ), - ), - const SizedBox(height: 12), - Row( - children: [ - _buildStatusBadge(doc['status']), - const SizedBox(width: 8), - _buildActionButton(doc['status']), - ], - ), - ], - ), - ), - ], - ), - ); - } - - Widget _getStatusIcon(String status) { - switch (status) { - case 'VERIFIED': - return const Icon( - LucideIcons.checkCircle, - color: Color(0xFF22C55E), - size: 20, - ); - case 'PENDING': - return const Icon( - LucideIcons.clock, - color: Color(0xFFF59E0B), - size: 20, - ); - default: - return const Icon( - LucideIcons.alertCircle, - color: Color(0xFFEF4444), - size: 20, - ); - } - } - - Widget _buildStatusBadge(String status) { - Color bg; - Color text; - String label = status; - - switch (status) { - case 'verified': - bg = const Color(0xFF10B981).withOpacity(0.2); - text = const Color(0xFF10B981); - break; - case 'PENDING': - bg = const Color(0xFFF59200).withOpacity(0.2); - text = const Color(0xFFF59200); - break; - case 'MISSING': - default: - bg = const Color(0xFFEF4444).withOpacity(0.2); - text = const Color(0xFFEF4444); - break; - } - - // Capitalize label - label = label[0].toUpperCase() + label.substring(1); - - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(12), - ), - child: Text( - label, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: text, - ), - ), - ); - } - - Widget _buildActionButton(String status) { - final bool isVerified = status == 'VERIFIED'; - return InkWell( - onTap: () {}, - borderRadius: BorderRadius.circular(4), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - child: Row( - children: [ - Icon( - isVerified ? LucideIcons.eye : LucideIcons.upload, - size: 16, - color: const Color(0xFF0A39DF), - ), - const SizedBox(width: 4), - Text( - isVerified ? 'View' : 'Upload', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF0A39DF), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/tax_forms_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/tax_forms_screen.dart deleted file mode 100644 index c1560544..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/tax_forms_screen.dart +++ /dev/null @@ -1,327 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; -import 'taxforms/form_i9_screen.dart'; -import 'taxforms/form_w4_screen.dart'; - -class TaxFormsScreen extends ConsumerStatefulWidget { - const TaxFormsScreen({super.key}); - - @override - ConsumerState createState() => _TaxFormsScreenState(); -} - -class _TaxFormsScreenState extends ConsumerState { - // Mock Data - final List> _taxForm = [ - { - 'formType': 'I9', - 'title': 'Form I-9', - 'subtitle': 'Employment Eligibility Verification', - 'description': 'Required to verify your identity and work authorization', - 'status': 'SUBMITTED', - 'icon': - '🛂', // Using text emoji as placeholder for custom icon or just use Lucide icon - }, - { - 'formType': 'W4', - 'title': 'Form W-4', - 'subtitle': 'Employee\'s Withholding Certificate', - 'description': 'Set up your federal tax withholding', - 'status': 'NOT_STARTED', - 'icon': '📋', - }, - ]; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: const Color(0xFF0A39DF), - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.arrowLeft, color: Colors.white), - onPressed: () => context.pop(), - ), - title: const Text( - 'Tax Documents', - style: TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - bottom: const PreferredSize( - preferredSize: Size.fromHeight(24), - child: Padding( - padding: EdgeInsets.only(left: 20, right: 20, bottom: 20), - child: Row( - children: [ - Expanded( - child: Text( - 'Complete required forms to start working', - style: TextStyle( - color: Color(0xCCFFFFFF), // white with opacity - fontSize: 14, - ), - ), - ), - ], - ), - ), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - children: [ - _buildProgressOverview(), - const SizedBox(height: 24), - ..._taxForm.map(_buildFormCard), - const SizedBox(height: 24), - _buildInfoCard(), - ], - ), - ), - ); - } - - Widget _buildProgressOverview() { - final completedCount = _taxForm - .where((f) => f['status'] == 'SUBMITTED' || f['status'] == 'APPROVED') - .length; - final totalCount = _taxForm.length; - final progress = totalCount > 0 ? completedCount / totalCount : 0.0; - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Document Progress', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: Color(0xFF121826), - ), - ), - Text( - '$completedCount/$totalCount', - style: const TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - ], - ), - const SizedBox(height: 12), - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: LinearProgressIndicator( - value: progress, - minHeight: 8, - backgroundColor: const Color(0xFFF3F4F6), - valueColor: const AlwaysStoppedAnimation( - Color(0xFF0A39DF), - ), - ), - ), - ], - ), - ); - } - - Widget _buildFormCard(Map form) { - return GestureDetector( - onTap: () { - if (form['formType'] == 'I9') { - context.push('/taxforms/i9'); - } else if (form['formType'] == 'W4') { - context.push('/taxforms/w4'); - } - }, - child: Container( - margin: const EdgeInsets.only(bottom: 16), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: const Color(0xFF0A39DF).withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: Text(form['icon'], style: const TextStyle(fontSize: 24)), - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - form['title'], - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: Color(0xFF121826), - ), - ), - _buildStatusBadge(form['status']), - ], - ), - const SizedBox(height: 4), - Text( - form['subtitle'], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF6A7382), - ), - ), - const SizedBox(height: 4), - Text( - form['description'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - ], - ), - ), - const SizedBox(width: 8), - const Icon( - LucideIcons.chevronRight, - color: Color(0xFF6A7382), - size: 20, - ), - ], - ), - ), - ); - } - - Widget _buildStatusBadge(String status) { - switch (status) { - case 'SUBMITTED': - case 'APPROVED': - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: const Color(0xFFF0FDF4), - borderRadius: BorderRadius.circular(12), - ), - child: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(LucideIcons.checkCircle, size: 12, color: Color(0xFF16A34A)), - SizedBox(width: 4), - Text( - 'Completed', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF16A34A), - ), - ), - ], - ), - ); - case 'DRAFT': - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: const Color(0xFFFFFBEB), - borderRadius: BorderRadius.circular(12), - ), - child: const Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(LucideIcons.clock, size: 12, color: Color(0xFFD97706)), - SizedBox(width: 4), - Text( - 'In Progress', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFFD97706), - ), - ), - ], - ), - ); - default: - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: const Color(0xFFF3F4F6), - borderRadius: BorderRadius.circular(12), - ), - child: const Text( - 'Not Started', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF6B7280), - ), - ), - ); - } - } - - Widget _buildInfoCard() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFEFF6FF), - borderRadius: BorderRadius.circular(16), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon(LucideIcons.fileText, color: Color(0xFF2563EB), size: 20), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Why are these needed?', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF1E3A8A), - ), - ), - SizedBox(height: 4), - Text( - 'I-9 and W-4 forms are required by federal law to verify your employment eligibility and set up correct tax withholding.', - style: TextStyle(fontSize: 14, color: Color(0xFF1D4ED8)), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart deleted file mode 100644 index d1a6dac8..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart +++ /dev/null @@ -1,905 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../../../../theme.dart'; - -class FormI9Screen extends StatefulWidget { - const FormI9Screen({super.key}); - - @override - State createState() => _FormI9ScreenState(); -} - -class _FormI9ScreenState extends State { - int _currentStep = 0; - bool _isSubmitting = false; - bool _isSuccess = false; - - final Map _formData = { - 'lastName': '', - 'firstName': '', - 'middleInitial': '', - 'otherLastNames': '', - 'address': '', - 'aptNumber': '', - 'city': '', - 'state': null, - 'zipCode': '', - 'dateOfBirth': '', - 'ssn': '', - 'email': '', - 'phone': '', - 'citizenshipStatus': '', - 'uscisNumber': '', - 'i94Number': '', - 'foreignPassportNumber': '', - 'countryOfIssuance': '', - 'expirationDate': '', - }; - - String _signature = ''; - - final List _usStates = [ - 'AL', - 'AK', - 'AZ', - 'AR', - 'CA', - 'CO', - 'CT', - 'DE', - 'FL', - 'GA', - 'HI', - 'ID', - 'IL', - 'IN', - 'IA', - 'KS', - 'KY', - 'LA', - 'ME', - 'MD', - 'MA', - 'MI', - 'MN', - 'MS', - 'MO', - 'MT', - 'NE', - 'NV', - 'NH', - 'NJ', - 'NM', - 'NY', - 'NC', - 'ND', - 'OH', - 'OK', - 'OR', - 'PA', - 'RI', - 'SC', - 'SD', - 'TN', - 'TX', - 'UT', - 'VT', - 'VA', - 'WA', - 'WV', - 'WI', - 'WY', - ]; - - final List> _steps = [ - {'title': 'Personal Information', 'subtitle': 'Name and contact details'}, - {'title': 'Address', 'subtitle': 'Your current address'}, - { - 'title': 'Citizenship Status', - 'subtitle': 'Work authorization verification', - }, - {'title': 'Review & Sign', 'subtitle': 'Confirm your information'}, - ]; - - void _updateField(String key, dynamic value) { - setState(() { - _formData[key] = value; - }); - } - - bool _canProceed() { - switch (_currentStep) { - case 0: - return _formData['lastName'].trim().isNotEmpty && - _formData['firstName'].trim().isNotEmpty && - _formData['dateOfBirth'].isNotEmpty && - _formData['ssn'].replaceAll(RegExp(r'\D'), '').length >= 4; - case 1: - return _formData['address'].trim().isNotEmpty && - _formData['city'].trim().isNotEmpty && - _formData['state'] != null && - _formData['zipCode'].length >= 5; - case 2: - return _formData['citizenshipStatus'].isNotEmpty; - case 3: - return _signature.trim().isNotEmpty; - default: - return true; - } - } - - void _handleNext() { - if (_currentStep < _steps.length - 1) { - setState(() => _currentStep++); - } else { - _submitForm(); - } - } - - void _handleBack() { - if (_currentStep > 0) { - setState(() => _currentStep--); - } - } - - Future _submitForm() async { - setState(() => _isSubmitting = true); - // Mock API call - await Future.delayed(const Duration(seconds: 2)); - if (mounted) { - setState(() { - _isSubmitting = false; - _isSuccess = true; - }); - } - } - - @override - Widget build(BuildContext context) { - if (_isSuccess) return _buildSuccessView(); - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - _buildHeader(), - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: _buildCurrentStep(), - ), - ), - _buildFooter(), - ], - ), - ); - } - - Widget _buildSuccessView() { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Center( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Container( - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: const Color(0xFFDCFCE7), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.check, - color: Color(0xFF16A34A), - size: 32, - ), - ), - const SizedBox(height: 16), - const Text( - 'Form I-9 Submitted!', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - 'Your form has been successfully submitted. Your employer will complete Section 2.', - textAlign: TextAlign.center, - style: TextStyle(color: AppColors.krowMuted), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: () => context.pop(), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: const Text('Back to Documents'), - ), - ), - ], - ), - ), - ), - ), - ); - } - - Widget _buildHeader() { - return Container( - color: AppColors.krowBlue, - padding: const EdgeInsets.only(top: 60, bottom: 24, left: 20, right: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 24, - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Form I-9', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - Text( - 'Employment Eligibility Verification', - style: TextStyle(color: Colors.white70, fontSize: 12), - ), - ], - ), - ], - ), - const SizedBox(height: 24), - Row( - children: _steps.asMap().entries.map((entry) { - final idx = entry.key; - final isLast = idx == _steps.length - 1; - return Expanded( - child: Row( - children: [ - Expanded( - child: Container( - height: 4, - decoration: BoxDecoration( - color: idx <= _currentStep - ? Colors.white - : Colors.white.withOpacity(0.3), - borderRadius: BorderRadius.circular(2), - ), - ), - ), - if (!isLast) const SizedBox(width: 4), - ], - ), - ); - }).toList(), - ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Step ${_currentStep + 1} of ${_steps.length}', - style: const TextStyle(color: Colors.white70, fontSize: 12), - ), - Text( - _steps[_currentStep]['title']!, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildCurrentStep() { - switch (_currentStep) { - case 0: - return _buildStep1(); - case 1: - return _buildStep2(); - case 2: - return _buildStep3(); - case 3: - return _buildStep4(); - default: - return Container(); - } - } - - Widget _buildTextField( - String label, - String key, { - TextInputType? keyboardType, - String? placeholder, - Function(String)? onChanged, - int? maxLength, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - TextField( - controller: TextEditingController(text: _formData[key]) - ..selection = TextSelection.fromPosition( - TextPosition(offset: (_formData[key] as String).length), - ), - onChanged: onChanged ?? (val) => _updateField(key, val), - keyboardType: keyboardType, - maxLength: maxLength, - decoration: InputDecoration( - hintText: placeholder, - hintStyle: TextStyle(color: Colors.grey[400]), - filled: true, - fillColor: Colors.white, - counterText: "", - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - ), - ), - ], - ); - } - - Widget _buildDropdown(String label, String key, List items) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - Container( - padding: const EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - value: _formData[key], - isExpanded: true, - hint: const Text('Select', style: TextStyle(color: Colors.grey)), - icon: const Icon( - LucideIcons.chevronDown, - size: 16, - color: AppColors.krowMuted, - ), - onChanged: (val) => _updateField(key, val), - items: items - .map( - (item) => DropdownMenuItem(value: item, child: Text(item)), - ) - .toList(), - ), - ), - ), - ], - ); - } - - Widget _buildStep1() { - return Column( - children: [ - Row( - children: [ - Expanded( - child: _buildTextField( - 'Last Name *', - 'lastName', - placeholder: 'Smith', - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildTextField( - 'First Name *', - 'firstName', - placeholder: 'John', - ), - ), - ], - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: _buildTextField( - 'Middle Initial', - 'middleInitial', - placeholder: 'A', - maxLength: 1, - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildTextField( - 'Other Last Names', - 'otherLastNames', - placeholder: 'If any', - ), - ), - ], - ), - const SizedBox(height: 16), - _buildTextField( - 'Date of Birth *', - 'dateOfBirth', - placeholder: 'YYYY-MM-DD', - keyboardType: TextInputType.datetime, - ), // Ideally use date picker - const SizedBox(height: 16), - _buildTextField( - 'Social Security Number *', - 'ssn', - placeholder: 'XXX-XX-XXXX', - keyboardType: TextInputType.number, - onChanged: (val) { - // Simple masking logic - String text = val.replaceAll(RegExp(r'\D'), ''); - if (text.length > 9) text = text.substring(0, 9); - // Add formatting if needed - _updateField('ssn', text); - }, - ), - const SizedBox(height: 16), - _buildTextField( - 'Email Address', - 'email', - placeholder: 'john@example.com', - keyboardType: TextInputType.emailAddress, - ), - const SizedBox(height: 16), - _buildTextField( - 'Phone Number', - 'phone', - placeholder: '(555) 123-4567', - keyboardType: TextInputType.phone, - ), - ], - ); - } - - Widget _buildStep2() { - return Column( - children: [ - _buildTextField( - 'Street Address *', - 'address', - placeholder: '123 Main Street', - ), - const SizedBox(height: 16), - _buildTextField('Apt. Number', 'aptNumber', placeholder: 'If any'), - const SizedBox(height: 16), - _buildTextField('City *', 'city', placeholder: 'San Francisco'), - const SizedBox(height: 16), - Row( - children: [ - Expanded(child: _buildDropdown('State *', 'state', _usStates)), - const SizedBox(width: 12), - Expanded( - child: _buildTextField( - 'ZIP Code *', - 'zipCode', - placeholder: '94102', - keyboardType: TextInputType.number, - maxLength: 5, - ), - ), - ], - ), - ], - ); - } - - Widget _buildStep3() { - return Column( - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue[50], - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - const Icon(LucideIcons.info, color: Color(0xFF2563EB), size: 20), - const SizedBox(width: 12), - const Expanded( - child: Text( - 'Select the option that describes your citizenship or immigration status.', - style: TextStyle(fontSize: 14, color: Color(0xFF1D4ED8)), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - _buildRadioOption('citizen', 'A citizen of the United States'), - const SizedBox(height: 12), - _buildRadioOption( - 'noncitizen_national', - 'A noncitizen national of the United States', - ), - const SizedBox(height: 12), - _buildRadioOption('permanent_resident', 'A lawful permanent resident'), - const SizedBox(height: 12), - _buildRadioOption('authorized_alien', 'An alien authorized to work'), - - if (_formData['citizenshipStatus'] == 'permanent_resident' || - _formData['citizenshipStatus'] == 'authorized_alien') - Padding( - padding: const EdgeInsets.only(top: 24), - child: Column( - children: [ - _buildTextField( - 'USCIS/A-Number', - 'uscisNumber', - placeholder: 'A-123456789', - ), - if (_formData['citizenshipStatus'] == 'authorized_alien') ...[ - const SizedBox(height: 16), - _buildTextField( - 'Expiration Date', - 'expirationDate', - placeholder: 'YYYY-MM-DD', - ), - ], - ], - ), - ), - ], - ); - } - - Widget _buildRadioOption(String value, String label) { - final isSelected = _formData['citizenshipStatus'] == value; - return GestureDetector( - onTap: () => _updateField('citizenshipStatus', value), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: isSelected ? AppColors.krowBlue : AppColors.krowBorder, - width: isSelected ? 2 : 1, - ), - ), - child: Row( - children: [ - Container( - width: 20, - height: 20, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: isSelected ? AppColors.krowBlue : Colors.grey, - width: isSelected ? 6 : 2, - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Text( - label, - style: const TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildStep4() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Information Summary', - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), - ), - const SizedBox(height: 12), - _buildSummaryRow( - 'Name', - '${_formData['firstName']} ${_formData['lastName']}', - ), - _buildSummaryRow( - 'SSN', - '***-**-${_formData['ssn'].length >= 4 ? _formData['ssn'].substring(_formData['ssn'].length - 4) : '****'}', - ), - _buildSummaryRow( - 'Address', - '${_formData['city']}, ${_formData['state']}', - ), - _buildSummaryRow( - 'Status', - _getStatusLabel(_formData['citizenshipStatus']), - ), - ], - ), - ), - const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFFFFBEB), - borderRadius: BorderRadius.circular(12), - ), - child: const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(LucideIcons.alertCircle, color: Color(0xFFD97706), size: 20), - SizedBox(width: 12), - Expanded( - child: Text( - 'I am aware that federal law provides for imprisonment and/or fines for false statements or the use of false documents in connection with the completion of this form.', - style: TextStyle(fontSize: 12, color: Color(0xFFB45309)), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - const Text( - 'Signature (type your full name) *', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - TextField( - onChanged: (val) => setState(() => _signature = val), - decoration: InputDecoration( - hintText: 'Type your full name', - filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - ), - style: const TextStyle( - fontFamily: 'Cursive', - fontSize: 18, - ), // Fallback font if Cursive not available - ), - const SizedBox(height: 16), - const Text( - 'Today\'s Date', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), - decoration: BoxDecoration( - color: const Color(0xFFF3F4F6), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Text( - DateTime.now().toString().split(' ')[0], - style: const TextStyle(color: AppColors.krowCharcoal), - ), - ), - ], - ); - } - - Widget _buildSummaryRow(String label, String value) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: const TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - Text( - value, - style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 14), - ), - ], - ), - ); - } - - String _getStatusLabel(String status) { - switch (status) { - case 'citizen': - return 'U.S. Citizen'; - case 'noncitizen_national': - return 'Noncitizen National'; - case 'permanent_resident': - return 'Permanent Resident'; - case 'authorized_alien': - return 'Authorized to Work'; - default: - return status; - } - } - - Widget _buildFooter() { - return Container( - padding: const EdgeInsets.all(16), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowBorder)), - ), - child: SafeArea( - child: Row( - children: [ - if (_currentStep > 0) - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 12), - child: OutlinedButton( - onPressed: _handleBack, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 16), - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.arrowLeft, size: 16), - SizedBox(width: 8), - Text( - 'Back', - style: TextStyle(color: AppColors.krowCharcoal), - ), - ], - ), - ), - ), - ), - Expanded( - flex: 2, - child: ElevatedButton( - onPressed: (_canProceed() && !_isSubmitting) - ? _handleNext - : null, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - disabledBackgroundColor: Colors.grey[300], - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: _isSubmitting - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - _currentStep == _steps.length - 1 - ? 'Submit Form' - : 'Continue', - ), - if (_currentStep < _steps.length - 1) ...[ - const SizedBox(width: 8), - const Icon(LucideIcons.arrowRight, size: 16), - ], - ], - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart deleted file mode 100644 index 3fdcc57b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart +++ /dev/null @@ -1,1056 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../../../../theme.dart'; - -class FormW4Screen extends StatefulWidget { - const FormW4Screen({super.key}); - - @override - State createState() => _FormW4ScreenState(); -} - -class _FormW4ScreenState extends State { - int _currentStep = 0; - bool _isSubmitting = false; - bool _isSuccess = false; - - final Map _formData = { - 'firstName': '', - 'lastName': '', - 'address': '', - 'cityStateZip': '', - 'ssn': '', - 'filingStatus': '', - 'multipleJobs': false, - 'qualifyingChildren': 0, - 'otherDependents': 0, - 'otherIncome': '', - 'deductions': '', - 'extraWithholding': '', - }; - - String _signature = ''; - - final List> _steps = [ - {'title': 'Personal Information', 'subtitle': 'Step 1'}, - {'title': 'Filing Status', 'subtitle': 'Step 1c'}, - {'title': 'Multiple Jobs', 'subtitle': 'Step 2 (optional)'}, - {'title': 'Dependents', 'subtitle': 'Step 3'}, - {'title': 'Other Adjustments', 'subtitle': 'Step 4 (optional)'}, - {'title': 'Review & Sign', 'subtitle': 'Step 5'}, - ]; - - void _updateField(String key, dynamic value) { - setState(() { - _formData[key] = value; - }); - } - - bool _canProceed() { - switch (_currentStep) { - case 0: - return _formData['firstName'].trim().isNotEmpty && - _formData['lastName'].trim().isNotEmpty && - _formData['ssn'].replaceAll(RegExp(r'\D'), '').length >= 4 && - _formData['address'].trim().isNotEmpty; - case 1: - return _formData['filingStatus'].isNotEmpty; - case 5: - return _signature.trim().isNotEmpty; - default: - return true; - } - } - - void _handleNext() { - if (_currentStep < _steps.length - 1) { - setState(() => _currentStep++); - } else { - _submitForm(); - } - } - - void _handleBack() { - if (_currentStep > 0) { - setState(() => _currentStep--); - } - } - - Future _submitForm() async { - setState(() => _isSubmitting = true); - // Mock API call - await Future.delayed(const Duration(seconds: 2)); - if (mounted) { - setState(() { - _isSubmitting = false; - _isSuccess = true; - }); - } - } - - int get _totalCredits { - return (_formData['qualifyingChildren'] as int) * 2000 + - (_formData['otherDependents'] as int) * 500; - } - - @override - Widget build(BuildContext context) { - if (_isSuccess) return _buildSuccessView(); - - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Column( - children: [ - _buildHeader(), - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: _buildCurrentStep(), - ), - ), - _buildFooter(), - ], - ), - ); - } - - Widget _buildSuccessView() { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: Center( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Container( - padding: const EdgeInsets.all(32), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(24), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - color: const Color(0xFFDCFCE7), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.check, - color: Color(0xFF16A34A), - size: 32, - ), - ), - const SizedBox(height: 16), - const Text( - 'Form W-4 Submitted!', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 8), - const Text( - 'Your withholding certificate has been submitted to your employer.', - textAlign: TextAlign.center, - style: TextStyle(color: AppColors.krowMuted), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: () => context.pop(), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: const Text('Back to Documents'), - ), - ), - ], - ), - ), - ), - ), - ); - } - - Widget _buildHeader() { - return Container( - color: AppColors.krowBlue, - padding: const EdgeInsets.only(top: 60, bottom: 24, left: 20, right: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 24, - ), - ), - const SizedBox(width: 12), - const Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Form W-4', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - Text( - 'Employee\'s Withholding Certificate', - style: TextStyle(color: Colors.white70, fontSize: 12), - ), - ], - ), - ], - ), - const SizedBox(height: 24), - Row( - children: _steps.asMap().entries.map((entry) { - final idx = entry.key; - final isLast = idx == _steps.length - 1; - return Expanded( - child: Row( - children: [ - Expanded( - child: Container( - height: 4, - decoration: BoxDecoration( - color: idx <= _currentStep - ? Colors.white - : Colors.white.withOpacity(0.3), - borderRadius: BorderRadius.circular(2), - ), - ), - ), - if (!isLast) const SizedBox(width: 4), - ], - ), - ); - }).toList(), - ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Step ${_currentStep + 1} of ${_steps.length}', - style: const TextStyle(color: Colors.white70, fontSize: 12), - ), - Text( - _steps[_currentStep]['title']!, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildCurrentStep() { - switch (_currentStep) { - case 0: - return _buildStep1(); - case 1: - return _buildStep2(); - case 2: - return _buildStep3(); - case 3: - return _buildStep4(); - case 4: - return _buildStep5(); - case 5: - return _buildStep6(); - default: - return Container(); - } - } - - Widget _buildTextField( - String label, - String key, { - TextInputType? keyboardType, - String? placeholder, - Function(String)? onChanged, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - TextField( - controller: TextEditingController(text: _formData[key].toString()) - ..selection = TextSelection.fromPosition( - TextPosition(offset: (_formData[key].toString()).length), - ), - onChanged: onChanged ?? (val) => _updateField(key, val), - keyboardType: keyboardType, - decoration: InputDecoration( - hintText: placeholder, - hintStyle: TextStyle(color: Colors.grey[400]), - filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - ), - ), - ], - ); - } - - Widget _buildStep1() { - return Column( - children: [ - Row( - children: [ - Expanded( - child: _buildTextField( - 'First Name *', - 'firstName', - placeholder: 'John', - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildTextField( - 'Last Name *', - 'lastName', - placeholder: 'Smith', - ), - ), - ], - ), - const SizedBox(height: 16), - _buildTextField( - 'Social Security Number *', - 'ssn', - placeholder: 'XXX-XX-XXXX', - keyboardType: TextInputType.number, - onChanged: (val) { - String text = val.replaceAll(RegExp(r'\D'), ''); - if (text.length > 9) text = text.substring(0, 9); - _updateField('ssn', text); - }, - ), - const SizedBox(height: 16), - _buildTextField('Address *', 'address', placeholder: '123 Main Street'), - const SizedBox(height: 16), - _buildTextField( - 'City, State, ZIP', - 'cityStateZip', - placeholder: 'San Francisco, CA 94102', - ), - ], - ); - } - - Widget _buildStep2() { - return Column( - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue[50], - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - const Icon(LucideIcons.info, color: Color(0xFF2563EB), size: 20), - const SizedBox(width: 12), - const Expanded( - child: Text( - 'Your filing status determines your standard deduction and tax rates.', - style: TextStyle(fontSize: 14, color: Color(0xFF1D4ED8)), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - _buildRadioOption( - 'single', - 'Single or Married filing separately', - null, - ), - const SizedBox(height: 12), - _buildRadioOption( - 'married', - 'Married filing jointly or Qualifying surviving spouse', - null, - ), - const SizedBox(height: 12), - _buildRadioOption( - 'head_of_household', - 'Head of household', - 'Check only if you\'re unmarried and pay more than half the costs of keeping up a home', - ), - ], - ); - } - - Widget _buildRadioOption(String value, String label, String? subLabel) { - final isSelected = _formData['filingStatus'] == value; - return GestureDetector( - onTap: () => _updateField('filingStatus', value), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: isSelected ? AppColors.krowBlue : AppColors.krowBorder, - width: isSelected ? 2 : 1, - ), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - margin: const EdgeInsets.only(top: 2), - width: 20, - height: 20, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: isSelected ? AppColors.krowBlue : Colors.grey, - width: isSelected ? 6 : 2, - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: const TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - if (subLabel != null) ...[ - const SizedBox(height: 4), - Text( - subLabel, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildStep3() { - return Column( - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.amber[50], - borderRadius: BorderRadius.circular(12), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon( - LucideIcons.helpCircle, - color: Color(0xFFD97706), - size: 20, - ), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'When to complete this step?', - style: TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFF92400E), - fontSize: 14, - ), - ), - SizedBox(height: 4), - Text( - 'Complete this step only if you hold more than one job at a time, or are married filing jointly and your spouse also works.', - style: TextStyle(fontSize: 12, color: Color(0xFFB45309)), - ), - ], - ), - ), - ], - ), - ), - const SizedBox(height: 24), - GestureDetector( - onTap: () => _updateField('multipleJobs', !_formData['multipleJobs']), - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: _formData['multipleJobs'] - ? AppColors.krowBlue - : AppColors.krowBorder, - ), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 24, - height: 24, - decoration: BoxDecoration( - color: _formData['multipleJobs'] - ? AppColors.krowBlue - : Colors.white, - borderRadius: BorderRadius.circular(6), - border: Border.all( - color: _formData['multipleJobs'] - ? AppColors.krowBlue - : Colors.grey, - ), - ), - child: _formData['multipleJobs'] - ? const Icon( - LucideIcons.check, - color: Colors.white, - size: 16, - ) - : null, - ), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'I have multiple jobs or my spouse works', - style: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - SizedBox(height: 4), - Text( - 'Check this box if there are only two jobs total', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - ], - ), - ), - ), - const SizedBox(height: 16), - const Text( - 'If this does not apply, you can continue to the next step', - textAlign: TextAlign.center, - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ], - ); - } - - Widget _buildStep4() { - return Column( - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.blue[50], - borderRadius: BorderRadius.circular(12), - ), - child: Row( - children: [ - const Icon(LucideIcons.info, color: Color(0xFF2563EB), size: 20), - const SizedBox(width: 12), - const Expanded( - child: Text( - 'If your total income will be \$200,000 or less (\$400,000 if married filing jointly), you may claim credits for dependents.', - style: TextStyle(fontSize: 14, color: Color(0xFF1D4ED8)), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - _buildCounter( - 'Qualifying children under age 17', - '\$2,000 each', - 'qualifyingChildren', - ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Divider(height: 1, color: AppColors.krowBorder), - ), - _buildCounter( - 'Other dependents', - '\$500 each', - 'otherDependents', - ), - ], - ), - ), - if (_totalCredits > 0) ...[ - const SizedBox(height: 16), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFDCFCE7), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Total credits (Step 3)', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF166534), - ), - ), - Text( - ' rastructure${_totalCredits}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - color: Color(0xFF15803D), - ), - ), - ], - ), - ), - ], - ], - ); - } - - Widget _buildCounter(String label, String badge, String key) { - int value = _formData[key] as int; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - label, - style: const TextStyle(fontWeight: FontWeight.w500), - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: const Color(0xFFDCFCE7), - borderRadius: BorderRadius.circular(12), - ), - child: Text( - badge, - style: const TextStyle( - fontSize: 10, - color: Color(0xFF15803D), - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - const SizedBox(height: 12), - Row( - children: [ - _buildCircleBtn( - LucideIcons.minus, - () => _updateField(key, value > 0 ? value - 1 : 0), - ), - SizedBox( - width: 48, - child: Text( - value.toString(), - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - _buildCircleBtn( - LucideIcons.plus, - () => _updateField(key, value + 1), - ), - ], - ), - ], - ); - } - - Widget _buildCircleBtn(IconData icon, VoidCallback onTap) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: AppColors.krowBorder), - color: Colors.white, - ), - child: Icon(icon, size: 20, color: AppColors.krowCharcoal), - ), - ); - } - - Widget _buildStep5() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'These adjustments are optional. You can skip them if they don\'t apply.', - style: TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - const SizedBox(height: 24), - _buildTextField( - '4(a) Other income (not from jobs)', - 'otherIncome', - placeholder: '\$0', - keyboardType: TextInputType.number, - ), - const Padding( - padding: EdgeInsets.only(top: 4, bottom: 16), - child: Text( - 'Include interest, dividends, retirement income', - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ), - - _buildTextField( - '4(b) Deductions', - 'deductions', - placeholder: '\$0', - keyboardType: TextInputType.number, - ), - const Padding( - padding: EdgeInsets.only(top: 4, bottom: 16), - child: Text( - 'If you expect to claim deductions other than the standard deduction', - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ), - - _buildTextField( - '4(c) Extra withholding', - 'extraWithholding', - placeholder: '\$0', - keyboardType: TextInputType.number, - ), - const Padding( - padding: EdgeInsets.only(top: 4, bottom: 16), - child: Text( - 'Additional tax to withhold each pay period', - style: TextStyle(fontSize: 12, color: AppColors.krowMuted), - ), - ), - ], - ); - } - - Widget _buildStep6() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Your W-4 Summary', - style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), - ), - const SizedBox(height: 12), - _buildSummaryRow( - 'Name', - '${_formData['firstName']} ${_formData['lastName']}', - ), - _buildSummaryRow( - 'SSN', - '***-**-${_formData['ssn'].length >= 4 ? _formData['ssn'].substring(_formData['ssn'].length - 4) : '****'}', - ), - _buildSummaryRow( - 'Filing Status', - _getFilingStatusLabel(_formData['filingStatus']), - ), - if (_totalCredits > 0) - _buildSummaryRow( - 'Credits', - '\$${_totalCredits}', - valueColor: Colors.green[700], - ), - ], - ), - ), - const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.amber[50], - borderRadius: BorderRadius.circular(12), - ), - child: const Text( - 'Under penalties of perjury, I declare that this certificate, to the best of my knowledge and belief, is true, correct, and complete.', - style: TextStyle(fontSize: 12, color: Color(0xFFB45309)), - ), - ), - const SizedBox(height: 24), - const Text( - 'Signature (type your full name) *', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - TextField( - onChanged: (val) => setState(() => _signature = val), - decoration: InputDecoration( - hintText: 'Type your full name', - filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 16, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBorder), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: const BorderSide(color: AppColors.krowBlue), - ), - ), - style: const TextStyle(fontFamily: 'Cursive', fontSize: 18), - ), - const SizedBox(height: 16), - const Text( - 'Date', - style: TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), - decoration: BoxDecoration( - color: const Color(0xFFF3F4F6), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Text( - DateTime.now().toString().split(' ')[0], - style: const TextStyle(color: AppColors.krowCharcoal), - ), - ), - ], - ); - } - - Widget _buildSummaryRow(String label, String value, {Color? valueColor}) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - label, - style: const TextStyle(color: AppColors.krowMuted, fontSize: 14), - ), - Text( - value, - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: valueColor ?? AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } - - String _getFilingStatusLabel(String status) { - switch (status) { - case 'single': - return 'Single'; - case 'married': - return 'Married'; - case 'head_of_household': - return 'Head of Household'; - default: - return status; - } - } - - Widget _buildFooter() { - return Container( - padding: const EdgeInsets.all(16), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowBorder)), - ), - child: SafeArea( - child: Row( - children: [ - if (_currentStep > 0) - Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 12), - child: OutlinedButton( - onPressed: _handleBack, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 16), - side: const BorderSide(color: AppColors.krowBorder), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.arrowLeft, size: 16), - SizedBox(width: 8), - Text( - 'Back', - style: TextStyle(color: AppColors.krowCharcoal), - ), - ], - ), - ), - ), - ), - Expanded( - flex: 2, - child: ElevatedButton( - onPressed: (_canProceed() && !_isSubmitting) - ? _handleNext - : null, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - disabledBackgroundColor: Colors.grey[300], - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - elevation: 0, - ), - child: _isSubmitting - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - _currentStep == _steps.length - 1 - ? 'Submit Form' - : 'Continue', - ), - if (_currentStep < _steps.length - 1) ...[ - const SizedBox(width: 8), - const Icon(LucideIcons.arrowRight, size: 16), - ], - ], - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/finances/bank_account_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/finances/bank_account_screen.dart deleted file mode 100644 index 9465ae2f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/finances/bank_account_screen.dart +++ /dev/null @@ -1,435 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class BankAccountScreen extends ConsumerStatefulWidget { - const BankAccountScreen({super.key}); - - @override - ConsumerState createState() => _BankAccountScreenState(); -} - -class _BankAccountScreenState extends ConsumerState { - bool _showForm = false; - - // Mock Data - final List> _accounts = [ - { - 'id': 1, - 'bank': 'Chase Bank', - 'type': 'CHECKING', - 'last4': '4523', - 'isPrimary': true, - }, - ]; - - // Form Controllers - final _routingController = TextEditingController(); - final _accountController = TextEditingController(); - String _selectedType = 'CHECKING'; - - @override - void dispose() { - _routingController.dispose(); - _accountController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Bank Account', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildSecurityNotice(), - const SizedBox(height: 24), - const Text( - 'Linked Accounts', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 12), - ..._accounts.map(_buildAccountCard), - - if (_showForm) ...[ - const SizedBox(height: 24), - _buildAddAccountForm(), - ], - // Add extra padding at bottom to avoid FAB overlap if needed - const SizedBox(height: 80), - ], - ), - ), - ), - if (!_showForm) - Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Color(0xFFE3E6E9))), - ), - child: SafeArea( - child: SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () => setState(() => _showForm = true), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0A39DF), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.plus, color: Colors.white, size: 20), - SizedBox(width: 8), - Text( - 'Add Bank Account', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - ), - ], - ), - ); - } - - Widget _buildSecurityNotice() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFF0A39DF).withOpacity(0.08), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Icon(LucideIcons.shield, color: Color(0xFF0A39DF), size: 20), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Secure & Encrypted', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: Color(0xFF121826), - ), - ), - SizedBox(height: 2), - Text( - 'Your banking information is encrypted and securely stored. We never share your details.', - style: TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildAccountCard(Map account) { - final bool isPrimary = account['isPrimary'] ?? false; - final Color primaryColor = const Color(0xFF0A39DF); - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: isPrimary ? primaryColor : const Color(0xFFE3E6E9), - width: isPrimary ? 2 : 1, - ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: primaryColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Icon( - LucideIcons.building2, - color: primaryColor, - size: 24, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - account['bank'], - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: Color(0xFF121826), - ), - ), - Text( - '${account['type']} •••• ${account['last4']}', - style: const TextStyle( - fontSize: 14, - color: Color(0xFF6A7382), - ), - ), - ], - ), - ], - ), - if (isPrimary) - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: primaryColor.withOpacity(0.15), - borderRadius: BorderRadius.circular(20), // Badge style - ), - child: Row( - children: [ - Icon(LucideIcons.check, size: 12, color: primaryColor), - const SizedBox(width: 4), - Text( - 'Primary', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: primaryColor, - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildAddAccountForm() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Add New Account', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 16, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 16), - _buildInputLabel('Routing Number'), - TextField( - controller: _routingController, - decoration: _inputDecoration('9 digits'), - keyboardType: TextInputType.number, - ), - const SizedBox(height: 16), - _buildInputLabel('Account Number'), - TextField( - controller: _accountController, - decoration: _inputDecoration('Enter account number'), - keyboardType: TextInputType.number, - ), - const SizedBox(height: 16), - _buildInputLabel('Account Type'), - Row( - children: [ - Expanded(child: _buildTypeButton('CHECKING')), - const SizedBox(width: 8), - Expanded(child: _buildTypeButton('SAVINGS')), - ], - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () => setState(() => _showForm = false), - style: OutlinedButton.styleFrom( - side: const BorderSide(color: Color(0xFFE3E6E9)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.symmetric(vertical: 12), - ), - child: const Text( - 'Cancel', - style: TextStyle(color: Color(0xFF121826)), - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: () { - // Mock add account - setState(() { - _accounts.add({ - 'id': DateTime.now().millisecondsSinceEpoch, - 'bank': 'New Bank', - 'type': _selectedType, - 'last4': _accountController.text.length > 4 - ? _accountController.text.substring( - _accountController.text.length - 4, - ) - : '0000', - 'isPrimary': false, - }); - _showForm = false; - _accountController.clear(); - _routingController.clear(); - }); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0A39DF), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.symmetric(vertical: 12), - elevation: 0, - ), - child: const Text( - 'Link Account', - style: TextStyle(color: Colors.white), - ), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildInputLabel(String label) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Text( - label, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ); - } - - InputDecoration _inputDecoration(String hint) { - return InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Color(0xFF9CA3AF)), - contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFF0A39DF)), - ), - ); - } - - Widget _buildTypeButton(String type) { - final bool isSelected = _selectedType == type; - return GestureDetector( - onTap: () => setState(() => _selectedType = type), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 10), - alignment: Alignment.center, - decoration: BoxDecoration( - color: isSelected - ? const Color(0xFFF1F5F9) - : Colors - .white, // Slight gray if selected? Or use OutlineButton style - // React uses Button variant="outline", which usually has gray border and white bg. - // There's no distinct active state style in the React code provided for the buttons other than they exist. - // Wait, the React code doesn't show active state styling for these buttons, just renders them. - // I will make them selectable visually. - borderRadius: BorderRadius.circular(6), - border: Border.all( - color: isSelected - ? const Color(0xFF0A39DF) - : const Color(0xFFE3E6E9), - ), - ), - child: Text( - type, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isSelected - ? const Color(0xFF0A39DF) - : const Color(0xFF121826), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/finances/time_card_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/finances/time_card_screen.dart deleted file mode 100644 index 1722f610..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/finances/time_card_screen.dart +++ /dev/null @@ -1,415 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'package:intl/intl.dart'; -import '../../../../theme.dart'; - -class TimeCardScreen extends ConsumerStatefulWidget { - const TimeCardScreen({super.key}); - - @override - ConsumerState createState() => _TimeCardScreenState(); -} - -class _TimeCardScreenState extends ConsumerState { - DateTime _selectedDate = DateTime.now(); - - // Mock Data - final List> _timesheets = [ - { - 'id': '1', - 'shiftId': '101', - 'date': DateTime.now() - .subtract(const Duration(days: 1)) - .toIso8601String(), - 'startTime': '09:00', - 'endTime': '17:00', - 'totalHours': 8.0, - 'hourlyRate': 20.0, - 'totalPay': 160.0, - 'status': 'PENDING', - 'shiftTitle': 'Line Cook', - 'clientName': 'Burger King', - 'location': 'Downtown', - }, - { - 'id': '2', - 'shiftId': '102', - 'date': DateTime.now() - .subtract(const Duration(days: 3)) - .toIso8601String(), - 'startTime': '10:00', - 'endTime': '16:00', - 'totalHours': 6.0, - 'hourlyRate': 18.0, - 'totalPay': 108.0, - 'status': 'APPROVED', - 'shiftTitle': 'Dishwasher', - 'clientName': 'The Pierre', - 'location': 'Upper East Side', - }, - { - 'id': '3', - 'shiftId': '103', - 'date': DateTime.now() - .subtract(const Duration(days: 10)) - .toIso8601String(), - 'startTime': '18:00', - 'endTime': '23:00', - 'totalHours': 5.0, - 'hourlyRate': 22.0, - 'totalPay': 110.0, - 'status': 'PAID', - 'shiftTitle': 'Bartender', - 'clientName': 'Rooftop Bar', - 'location': 'Midtown', - }, - ]; - - @override - Widget build(BuildContext context) { - // Filter timesheets by selected month/year - final filteredTimesheets = _timesheets.where((t) { - final date = DateTime.parse(t['date']); - return date.month == _selectedDate.month && - date.year == _selectedDate.year; - }).toList(); - - final totalHours = filteredTimesheets.fold( - 0.0, - (sum, t) => sum + (t['totalHours'] as double), - ); - final totalEarnings = filteredTimesheets.fold( - 0.0, - (sum, t) => sum + (t['totalPay'] as double), - ); - - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Timecard', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - children: [ - _buildMonthSelector(), - const SizedBox(height: 24), - _buildSummary(totalHours, totalEarnings), - const SizedBox(height: 24), - _buildShiftHistory(filteredTimesheets), - ], - ), - ), - ); - } - - Widget _buildMonthSelector() { - return Container( - padding: const EdgeInsets.all( - 4, - ), // React uses p-3, but row layout needs space - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () { - setState(() { - _selectedDate = DateTime( - _selectedDate.year, - _selectedDate.month - 1, - ); - }); - }, - ), - Text( - DateFormat('MMM yyyy').format(_selectedDate), - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF121826), - ), - ), - IconButton( - icon: const Icon( - LucideIcons.chevronRight, - color: Color(0xFF6A7382), - ), - onPressed: () { - setState(() { - _selectedDate = DateTime( - _selectedDate.year, - _selectedDate.month + 1, - ); - }); - }, - ), - ], - ), - ); - } - - Widget _buildSummary(double totalHours, double totalEarnings) { - return Row( - children: [ - Expanded( - child: _buildSummaryCard( - LucideIcons.clock, - 'Hours Worked', - totalHours.toStringAsFixed(1), - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildSummaryCard( - LucideIcons.dollarSign, - 'Total Earnings', - '\$${totalEarnings.toStringAsFixed(2)}', - ), - ), - ], - ); - } - - Widget _buildSummaryCard(IconData icon, String label, String value) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 16, color: const Color(0xFF0A39DF)), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ), - const SizedBox(height: 8), - Text( - value, - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - ], - ), - ); - } - - Widget _buildShiftHistory(List> timesheets) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Shift History', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 12), - if (timesheets.isEmpty) - const Center( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 48), - child: Column( - children: [ - Icon(LucideIcons.clock, size: 48, color: Color(0xFF6A7382)), - SizedBox(height: 12), - Text( - 'No shifts for this month', - style: TextStyle(color: Color(0xFF6A7382)), - ), - ], - ), - ), - ) - else - ...timesheets.map(_buildTimesheetCard), - ], - ); - } - - Widget _buildTimesheetCard(Map timesheet) { - final status = timesheet['status']; - Color statusBg; - Color statusColor; - - switch (status) { - case 'APPROVED': - statusBg = const Color(0xFF10B981).withOpacity(0.12); - statusColor = const Color(0xFF10B981); // Green - break; - case 'DISPUTED': - statusBg = const Color(0xFFEF4444).withOpacity(0.12); - statusColor = const Color(0xFFEF4444); // Red - break; - case 'PAID': - statusBg = const Color(0xFF0A39DF).withOpacity(0.12); - statusColor = const Color(0xFF0A39DF); // Blue - break; - case 'PENDING': - default: - statusBg = const Color(0xFFF59200).withOpacity(0.12); - statusColor = const Color(0xFFF59200); // Orange - break; - } - - final date = DateTime.parse(timesheet['date']); - final dateStr = DateFormat('EEE, MMM d').format(date); - - // Format times: 09:00 -> 9:00 AM - String formatTime(String t) { - if (t.isEmpty) return '--:--'; - final parts = t.split(':'); - final dt = DateTime(2000, 1, 1, int.parse(parts[0]), int.parse(parts[1])); - return DateFormat('h:mm a').format(dt); - } - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - timesheet['shiftTitle'], - style: const TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - Text( - timesheet['clientName'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - ], - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: statusBg, - borderRadius: BorderRadius.circular(20), - ), - child: Text( - status.toString().replaceFirst( - status[0], - status[0].toUpperCase(), - ), - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: statusColor, - ), - ), - ), - ], - ), - const SizedBox(height: 12), - Wrap( - spacing: 12, - runSpacing: 4, - children: [ - _buildIconText(LucideIcons.calendar, dateStr), - _buildIconText( - LucideIcons.clock, - '${formatTime(timesheet['startTime'])} - ${formatTime(timesheet['endTime'])}', - ), - if (timesheet['location'] != null) - _buildIconText(LucideIcons.mapPin, timesheet['location']), - ], - ), - const SizedBox(height: 12), - Container( - padding: const EdgeInsets.only(top: 12), - decoration: const BoxDecoration( - border: Border(top: BorderSide(color: Color(0xFFE3E6E9))), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '${timesheet['totalHours'].toStringAsFixed(1)} hours @ \$${timesheet['hourlyRate']}/hr', - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - Text( - '\$${timesheet['totalPay'].toStringAsFixed(2)}', - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFF0A39DF), - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildIconText(IconData icon, String text) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(icon, size: 14, color: const Color(0xFF6A7382)), - const SizedBox(width: 4), - Text( - text, - style: const TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/krow_university_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/krow_university_screen.dart deleted file mode 100644 index 7782292d..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/krow_university_screen.dart +++ /dev/null @@ -1,820 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class KrowUniversityScreen extends ConsumerStatefulWidget { - const KrowUniversityScreen({super.key}); - - @override - ConsumerState createState() => - _KrowUniversityScreenState(); -} - -class _KrowUniversityScreenState extends ConsumerState { - String _activeCategory = 'all'; - - // Mock Data - final Map _staff = { - 'level': 'Krower I', - 'xp': 1250, - 'badges': [], - }; - - final List> _levels = [ - { - 'name': 'Krower I', - 'xpRequired': 0, - 'icon': LucideIcons.award, - 'colors': [Color(0xFF333F48), Color(0xFF4A5A64)], - }, - { - 'name': 'Krower II', - 'xpRequired': 500, - 'icon': LucideIcons.star, - 'colors': [Color(0xFF0032A0), Color(0xFF0047CC)], - }, - { - 'name': 'Krower III', - 'xpRequired': 1500, - 'icon': LucideIcons.sparkles, - 'colors': [Color(0xFF0032A0), Color(0xFF333F48)], - }, - { - 'name': 'Krower Elite', - 'xpRequired': 3500, - 'icon': LucideIcons.crown, - 'colors': [Color(0xFFF7E600), Color(0xFFF8E08E)], - }, - ]; - - final List> _categories = [ - {'categoryId': 'all', 'label': 'All', 'icon': LucideIcons.graduationCap}, - {'categoryId': 'food_safety', 'label': 'Food Safety', 'icon': LucideIcons.award}, - {'categoryId': 'hospitality', 'label': 'Hospitality', 'icon': LucideIcons.star}, - {'categoryId': 'warehouse', 'label': 'Warehouse', 'icon': LucideIcons.award}, - {'categoryId': 'leadership', 'label': 'Leadership', 'icon': LucideIcons.award}, - ]; - - final List> _courses = [ - { - 'id': '1', - 'title': 'Introduction to Food Safety', - 'description': 'Learn the basics of food handling and safety protocols.', - 'category': 'food_safety', - 'durationMinutes': 30, - 'xpReward': 100, - 'levelRequired': 'Krower I', - 'isCertification': true, - 'progressPercent': 100, - 'completed': true, - }, - { - 'id': '2', - 'title': 'Advanced Customer Service', - 'description': 'Master the art of hospitality and guest satisfaction.', - 'category': 'hospitality', - 'durationMinutes': 45, - 'xpReward': 150, - 'levelRequired': 'Krower I', - 'isCertification': false, - 'progressPercent': 45, - 'completed': false, - }, - { - 'id': '3', - 'title': 'Warehouse Operations 101', - 'description': - 'Essential safety and operational guidelines for warehouse work.', - 'category': 'warehouse', - 'durationMinutes': 60, - 'xpReward': 200, - 'levelRequired': 'Krower II', - 'isCertification': true, - 'progressPercent': 0, - 'completed': false, - }, - { - 'id': '4', - 'title': 'Team Leadership Fundamentals', - 'description': 'Developing core leadership skills for shift supervisors.', - 'category': 'leadership', - 'durationMinutes': 90, - 'xpReward': 300, - 'levelRequired': 'Krower III', - 'isCertification': true, - 'progressPercent': 0, - 'completed': false, - }, - ]; - - final List _certifications = [ - 'Food Handler', - 'Alcohol Safety', - 'First Aid', - 'OSHA', - ]; - - @override - Widget build(BuildContext context) { - final filteredCourses = _activeCategory == 'all' - ? _courses - : _courses.where((c) => c['category'] == _activeCategory).toList(); - - final completedCount = _courses.where((c) => c['completed'] == true).length; - final totalXpEarned = _staff['xp']; - - return Scaffold( - backgroundColor: const Color(0xFFF8F9FA), - body: SingleChildScrollView( - padding: const EdgeInsets.only(bottom: 100), - child: Column( - children: [ - _buildHeader(completedCount, totalXpEarned), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 20), - _buildLevelProgress(), - const SizedBox(height: 24), - _buildCategories(), - const SizedBox(height: 24), - _buildSectionHeader( - _activeCategory == 'all' - ? 'All Courses' - : _categories.firstWhere( - (c) => c['categoryId'] == _activeCategory, - )['label'], - null, - ), - _buildCoursesList(filteredCourses), - _buildSectionHeader('Certifications', null), - _buildCertificationsGrid(), - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader(int completedCount, int totalXp) { - return Container( - width: double.infinity, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Color(0xFF7C3AED), Color(0xFF6D28D9)], - ), - ), - padding: const EdgeInsets.fromLTRB(20, 60, 20, 32), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - GestureDetector( - onTap: () => context.pop(), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.arrowLeft, - color: Colors.white, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - const Text( - 'KROW University', - style: TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 24), - Row( - children: [ - Expanded( - child: _buildStatCard(_courses.length.toString(), 'Courses'), - ), - const SizedBox(width: 12), - Expanded( - child: _buildStatCard(completedCount.toString(), 'Completed'), - ), - const SizedBox(width: 12), - Expanded(child: _buildStatCard(totalXp.toString(), 'XP')), - ], - ), - ], - ), - ); - } - - Widget _buildStatCard(String value, String label) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(12), - ), - child: Column( - children: [ - Text( - value, - style: const TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - Text( - label, - style: const TextStyle(color: Color(0xFFDDD6FE), fontSize: 12), - ), - ], - ), - ); - } - - Widget _buildLevelProgress() { - final String currentLevelName = _staff['level']; - final int xp = _staff['xp']; - final List badges = List.from(_staff['badges']); - - final currentLevelIndex = _levels.indexWhere( - (l) => l['name'] == currentLevelName, - ); - final currentLevel = currentLevelIndex != -1 - ? _levels[currentLevelIndex] - : _levels[0]; - final nextLevel = currentLevelIndex + 1 < _levels.length - ? _levels[currentLevelIndex + 1] - : null; - - final double progressToNext = nextLevel != null - ? ((xp - currentLevel['xpRequired']) / - (nextLevel['xpRequired'] - currentLevel['xpRequired'])) - .clamp(0.0, 1.0) - : 1.0; - - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - border: Border.all(color: const Color(0xFFF1F5F9)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Your Level', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), - ), - const Icon( - LucideIcons.chevronRight, - size: 20, - color: Color(0xFF94A3B8), - ), - ], - ), - const SizedBox(height: 20), - Row( - children: [ - Container( - width: 64, - height: 64, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: currentLevel['colors'], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: (currentLevel['colors'][0] as Color).withOpacity( - 0.3, - ), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Icon( - currentLevel['icon'], - color: Colors.white, - size: 32, - ), - ), - const SizedBox(width: 16), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - currentLevel['name'], - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - Text( - '$xp XP earned', - style: const TextStyle( - fontSize: 14, - color: Color(0xFF64748B), - ), - ), - ], - ), - ], - ), - if (nextLevel != null) ...[ - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Progress to ${nextLevel['name']}', - style: const TextStyle( - fontSize: 14, - color: Color(0xFF64748B), - ), - ), - Text( - '${(progressToNext * 100).toInt()}%', - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ], - ), - const SizedBox(height: 8), - ClipRRect( - borderRadius: BorderRadius.circular(6), - child: LinearProgressIndicator( - value: progressToNext, - minHeight: 12, - backgroundColor: const Color(0xFFF1F5F9), - valueColor: AlwaysStoppedAnimation( - nextLevel['colors'][1], - ), - ), - ), - const SizedBox(height: 8), - Text( - '${nextLevel['xpRequired'] - xp} XP to go', - style: const TextStyle(fontSize: 12, color: Color(0xFF94A3B8)), - ), - ], - const SizedBox(height: 20), - Text( - 'Badges Earned (${badges.length})', - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), - ), - ), - const SizedBox(height: 8), - if (badges.isEmpty) - const Text( - 'Complete courses to earn badges!', - style: TextStyle(fontSize: 14, color: Color(0xFF94A3B8)), - ) - else - Wrap( - spacing: 8, - children: badges.map((b) => _buildBadgeChip(b)).toList(), - ), - const SizedBox(height: 16), - // Level Benefits - if (nextLevel != null) - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - const Color(0xFFF8E08E).withOpacity(0.3), - const Color(0xFFF7E600).withOpacity(0.2), - ], - ), - borderRadius: BorderRadius.circular(12), - ), - child: Text( - '🎯 Reach ${nextLevel['name']} to unlock premium shifts & +\$2/hr bonus!', - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF333F48), - ), - ), - ), - ], - ), - ); - } - - Widget _buildBadgeChip(String label) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - const Color(0xFF0032A0).withOpacity(0.05), - const Color(0xFF0032A0).withOpacity(0.1), - ], - ), - border: Border.all(color: const Color(0xFF0032A0).withOpacity(0.2)), - borderRadius: BorderRadius.circular(8), - ), - child: Text( - label, - style: const TextStyle(color: Color(0xFF0032A0), fontSize: 12), - ), - ); - } - - Widget _buildCategories() { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - clipBehavior: Clip.none, - child: Row( - children: _categories.map((cat) { - final bool isActive = _activeCategory == cat['categoryId']; - return Padding( - padding: const EdgeInsets.only(right: 8), - child: GestureDetector( - onTap: () => setState(() => _activeCategory = cat['categoryId']), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 10, - ), - decoration: BoxDecoration( - color: isActive ? const Color(0xFF7C3AED) : Colors.white, - borderRadius: BorderRadius.circular(24), - border: isActive - ? null - : Border.all(color: const Color(0xFFE2E8F0)), - boxShadow: isActive - ? [ - BoxShadow( - color: const Color(0xFF7C3AED).withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ] - : null, - ), - child: Row( - children: [ - Icon( - cat['icon'], - size: 16, - color: isActive ? Colors.white : const Color(0xFF64748B), - ), - const SizedBox(width: 8), - Text( - cat['label'], - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isActive - ? Colors.white - : const Color(0xFF64748B), - ), - ), - ], - ), - ), - ), - ); - }).toList(), - ), - ); - } - - Widget _buildSectionHeader(String title, String? action) { - return Text( - title, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ); - } - - Widget _buildCoursesList(List> courses) { - if (courses.isEmpty) { - return Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 40), - child: Column( - children: [ - const Icon( - LucideIcons.graduationCap, - size: 48, - color: Color(0xFFCBD5E1), - ), - const SizedBox(height: 12), - const Text( - 'No courses in this category yet', - style: TextStyle(color: Color(0xFF64748B)), - ), - ], - ), - ), - ); - } - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: courses.length, - itemBuilder: (context, index) { - final course = courses[index]; - final bool isCompleted = course['completed']; - final bool isLocked = - course['levelRequired'] != 'Krower I' && - _staff['level'] != course['levelRequired']; - final double progress = - (course['progressPercent'] as num).toDouble() / 100; - - return Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 5, - offset: const Offset(0, 2), - ), - ], - ), - child: Opacity( - opacity: isLocked ? 0.6 : 1.0, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - children: [ - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFF5F3FF), Color(0xFFEDE9FE)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12), - ), - child: Center( - child: isLocked - ? const Icon( - LucideIcons.lock, - color: Color(0xFF94A3B8), - ) - : isCompleted - ? const Icon( - LucideIcons.checkCircle, - color: Color(0xFF10B981), - size: 32, - ) - : const Icon( - LucideIcons.play, - color: Color(0xFF7C3AED), - size: 24, - ), - ), - ), - if (course['isCertification']) - Positioned( - top: -4, - right: -4, - child: Container( - padding: const EdgeInsets.all(4), - decoration: const BoxDecoration( - color: Color(0xFFF59E0B), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.award, - color: Colors.white, - size: 10, - ), - ), - ), - ], - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - course['title'], - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - const Icon( - LucideIcons.chevronRight, - size: 20, - color: Color(0xFF94A3B8), - ), - ], - ), - const SizedBox(height: 4), - Text( - course['description'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 12), - Row( - children: [ - _buildBadge( - LucideIcons.clock, - '${course['durationMinutes']} min', - ), - const SizedBox(width: 8), - _buildXpBadge('+${course['xpReward']} XP'), - ], - ), - if (progress > 0 && !isCompleted) ...[ - const SizedBox(height: 12), - ClipRRect( - borderRadius: BorderRadius.circular(2), - child: LinearProgressIndicator( - value: progress, - minHeight: 4, - backgroundColor: const Color(0xFFF1F5F9), - valueColor: const AlwaysStoppedAnimation( - Color(0xFF7C3AED), - ), - ), - ), - const SizedBox(height: 4), - Text( - '${(progress * 100).toInt()}% complete', - style: const TextStyle( - fontSize: 10, - color: Color(0xFF94A3B8), - ), - ), - ], - if (isLocked) ...[ - const SizedBox(height: 8), - Text( - '🔒 Requires ${course['levelRequired']}', - style: const TextStyle( - fontSize: 12, - color: Color(0xFFD97706), - fontWeight: FontWeight.w500, - ), - ), - ], - ], - ), - ), - ], - ), - ), - ); - }, - ); - } - - Widget _buildBadge(IconData icon, String text) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(4), - border: Border.all(color: const Color(0xFFE2E8F0)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(icon, size: 12, color: const Color(0xFF64748B)), - const SizedBox(width: 4), - Text( - text, - style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)), - ), - ], - ), - ); - } - - Widget _buildXpBadge(String text) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: const Color(0xFFF5F3FF), - borderRadius: BorderRadius.circular(4), - border: Border.all(color: const Color(0xFFDDD6FE)), - ), - child: Text( - text, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: Color(0xFF7C3AED), - ), - ), - ); - } - - Widget _buildCertificationsGrid() { - return GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - mainAxisSpacing: 12, - crossAxisSpacing: 12, - childAspectRatio: 1.5, - ), - itemCount: _certifications.length, - itemBuilder: (context, index) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: const LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [Color(0xFFFFFBEB), Color(0xFFFEF3C7)], - ), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: const Color(0xFFFEF3C7)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Icon(LucideIcons.award, color: Color(0xFFD97706), size: 32), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _certifications[index], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), - ), - const Text( - 'Certification', - style: TextStyle(fontSize: 11, color: Color(0xFF64748B)), - ), - ], - ), - ], - ), - ); - }, - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart deleted file mode 100644 index 98d389bf..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart +++ /dev/null @@ -1,450 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; - -class LeaderboardScreen extends ConsumerStatefulWidget { - const LeaderboardScreen({super.key}); - - @override - ConsumerState createState() => _LeaderboardScreenState(); -} - -class _LeaderboardScreenState extends ConsumerState { - String _activeTab = 'weekly'; - - // Mock Data - final List> _profiles = [ - { - 'id': '1', - 'fullName': 'Sarah Jenkins', - 'photoUrl': null, - 'xp': 2500, - 'level': 'Krower III', - 'userId': 'sarah@example.com', - }, - { - 'id': '2', - 'fullName': 'Mike Ross', - 'photoUrl': null, - 'xp': 2350, - 'level': 'Krower II', - 'userId': 'mike@example.com', - }, - { - 'id': '3', - 'fullName': 'Jessica Lee', - 'photoUrl': null, - 'xp': 2100, - 'level': 'Krower II', - 'userId': 'jessica@example.com', - }, - { - 'id': '4', - 'fullName': 'Krower (You)', - 'photoUrl': null, - 'xp': 1250, - 'level': 'Krower I', - 'userId': 'me@krow.com', // Current user - }, - { - 'id': '5', - 'fullName': 'David Chen', - 'photoUrl': null, - 'xp': 900, - 'level': 'Krower I', - 'userId': 'david@example.com', - }, - { - 'id': '6', - 'fullName': 'Emily Clark', - 'photoUrl': null, - 'xp': 850, - 'level': 'Krower I', - 'userId': 'emily@example.com', - }, - ]; - - @override - Widget build(BuildContext context) { - // Sort profiles by XP desc - final sortedProfiles = List>.from(_profiles); - sortedProfiles.sort((a, b) => (b['xp'] as int).compareTo(a['xp'] as int)); - - final topThree = sortedProfiles.take(3).toList(); - final rest = sortedProfiles.skip(3).toList(); - - // Find my rank - final myIndex = sortedProfiles.indexWhere( - (p) => p['userId'] == 'me@krow.com', - ); - final myRank = myIndex + 1; - - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Leaderboard', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - children: [ - _buildTabs(), - const SizedBox(height: 24), - _buildPodium(topThree), - const SizedBox(height: 24), - if (myRank > 0) ...[ - _buildMyRank(myRank), - const SizedBox(height: 16), - ], - _buildRestList(rest, 4), // Starting rank 4 - ], - ), - ), - ); - } - - Widget _buildTabs() { - final tabs = ['weekly', 'monthly', 'all-time']; - return Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: const Color(0xFFE3E6E9), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: tabs.map((tab) { - final isActive = _activeTab == tab; - return Expanded( - child: GestureDetector( - onTap: () => setState(() => _activeTab = tab), - child: Container( - padding: const EdgeInsets.symmetric(vertical: 8), - alignment: Alignment.center, - decoration: BoxDecoration( - color: isActive ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(6), - ), - child: Text( - tab[0].toUpperCase() + tab.substring(1), - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isActive - ? const Color(0xFF121826) - : const Color(0xFF6A7382), - ), - ), - ), - ), - ); - }).toList(), - ), - ); - } - - Widget _buildPodium(List> topThree) { - if (topThree.isEmpty) return const SizedBox.shrink(); - - return SizedBox( - height: 300, // Increased height to prevent overflow - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // 2nd Place (Left) - if (topThree.length > 1) - Expanded( - child: _buildPodiumItem( - topThree[1], - 2, - const Color(0xFFC0C0C0), - 160, - ), - ), - - // 1st Place (Center - Taller) - Expanded( - child: _buildPodiumItem( - topThree[0], - 1, - const Color(0xFFF9E547), - 200, - ), - ), // Yellow/Gold - // 3rd Place (Right) - if (topThree.length > 2) - Expanded( - child: _buildPodiumItem( - topThree[2], - 3, - const Color(0xFFCD7F32), - 140, - ), - ), // Bronze - ], - ), - ); - } - - Widget _buildPodiumItem( - Map profile, - int rank, - Color color, - double height, - ) { - // Height determines the stand height + avatar space. - // The visual in React has a stand. - - // React styles: - // 2nd: Avatar border #C0C0C0, bg #C0C0C020, stand #C0C0C030 - // 1st: Avatar border accent (#F9E547), stand accent30 - // 3rd: Avatar border #CD7F32, stand #CD7F3220 - - final Color standColor = color.withOpacity(0.2); // approx - final String firstName = profile['fullName'].split(' ')[0]; - - return Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (rank == 1) - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Icon(LucideIcons.trophy, color: color, size: 32), - ) - else - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Icon(LucideIcons.medal, color: color, size: 24), - ), - - Container( - width: rank == 1 ? 80 : 64, - height: rank == 1 ? 80 : 64, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all(color: color, width: 3), - image: profile['photoUrl'] != null - ? DecorationImage( - image: NetworkImage(profile['photoUrl']), - fit: BoxFit.cover, - ) - : null, - color: standColor, - ), - child: profile['photoUrl'] == null - ? Center( - child: Text( - firstName[0], - style: TextStyle( - fontSize: rank == 1 ? 32 : 24, - fontWeight: FontWeight.bold, - color: const Color(0xFF6A7382), // Muted text for fallback - ), - ), - ) - : null, - ), - const SizedBox(height: 8), - Text( - firstName, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: Color(0xFF121826), - ), - ), - Text( - '${profile['xp']} XP', - style: const TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 8), - Container( - width: 64, - height: rank == 1 ? 96 : (rank == 2 ? 64 : 48), // stand height - decoration: BoxDecoration( - color: standColor, - borderRadius: const BorderRadius.vertical(top: Radius.circular(8)), - ), - ), - ], - ); - } - - Widget _buildMyRank(int rank) { - // React style: bg primary10 (#0A39DF1A), border primary30 - const primary = Color(0xFF0A39DF); - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: primary.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - border: Border.all(color: primary.withOpacity(0.3)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Text( - '#$rank', - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: primary, - ), - ), - const SizedBox(width: 12), - const Text( - 'Your Rank', - style: TextStyle( - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ], - ), - const Row( - children: [ - Icon(LucideIcons.trendingUp, size: 16, color: primary), - SizedBox(width: 4), - Text( - '+5', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: primary, - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildRestList(List> rest, int startRank) { - return Column( - children: rest.asMap().entries.map((entry) { - final index = entry.key; - final profile = entry.value; - final rank = startRank + index; - - return Container( - margin: const EdgeInsets.only(bottom: 8), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Row( - children: [ - SizedBox( - width: 32, - child: Text( - '#$rank', - textAlign: TextAlign.center, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFF6A7382), - ), - ), - ), - const SizedBox(width: 12), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: const Color(0xFF0A39DF).withOpacity(0.1), - image: profile['photoUrl'] != null - ? DecorationImage( - image: NetworkImage(profile['photoUrl']), - fit: BoxFit.cover, - ) - : null, - ), - child: profile['photoUrl'] == null - ? Center( - child: Text( - profile['fullName'][0], - style: const TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xFF0A39DF), - ), - ), - ) - : null, - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - profile['fullName'], - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: Color(0xFF121826), - ), - ), - Text( - profile['level'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - ], - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Row( - children: [ - const Icon( - LucideIcons.star, - size: 12, - color: Color(0xFFEAB308), - ), // Amber for star - const SizedBox(width: 4), - Text( - '${profile['xp']} XP', - style: const TextStyle( - fontSize: 12, - color: Color(0xFF121826), - ), - ), - ], - ), - ), - ], - ), - ); - }).toList(), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/trainings_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/trainings_screen.dart deleted file mode 100644 index cb3423c6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/level_up/trainings_screen.dart +++ /dev/null @@ -1,329 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class TrainingsScreen extends ConsumerStatefulWidget { - const TrainingsScreen({super.key}); - - @override - ConsumerState createState() => _TrainingsScreenState(); -} - -class _TrainingsScreenState extends ConsumerState { - // Mock Data - final List> _courses = [ - { - 'id': '1', - 'title': 'Introduction to Food Safety', - 'description': 'Learn the basics of food handling and safety protocols.', - 'durationMinutes': 30, - 'xpReward': 100, - 'thumbnailUrl': null, // Use default icon - 'progressPercent': 100, - 'completed': true, - }, - { - 'id': '2', - 'title': 'Advanced Customer Service', - 'description': 'Master the art of hospitality and guest satisfaction.', - 'durationMinutes': 45, - 'xpReward': 150, - 'thumbnailUrl': null, - 'progressPercent': 45, - 'completed': false, - }, - { - 'id': '3', - 'title': 'Warehouse Safety Standards', - 'description': 'Comprehensive guide to warehouse safety.', - 'durationMinutes': 60, - 'xpReward': 200, - 'thumbnailUrl': null, - 'progressPercent': 0, - 'completed': false, - }, - ]; - - @override - Widget build(BuildContext context) { - // Calculate stats - final int completedCount = _courses.where((c) => c['completed']).length; - final int inProgressCount = _courses - .where((c) => !c['completed'] && (c['progressPercent'] as int) > 0) - .length; - final int totalXp = _courses - .where((c) => c['completed']) - .fold(0, (sum, c) => sum + (c['xpReward'] as int)); - - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Trainings', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), - child: Column( - children: [ - _buildStatsRow(completedCount, inProgressCount, totalXp), - const SizedBox(height: 24), - _buildCourseList(), - ], - ), - ), - ); - } - - Widget _buildStatsRow(int completed, int inProgress, int xp) { - return Row( - children: [ - Expanded( - child: _buildStatCard( - completed.toString(), - 'Completed', - const Color(0xFF0A39DF), - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildStatCard( - inProgress.toString(), - 'In Progress', - const Color(0xFF121826), - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildStatCard( - xp.toString(), - 'XP Earned', - const Color(0xFFF9E547), - ), - ), // Note: yellow text might be hard to read on white? React uses this color for text. - ], - ); - } - - Widget _buildStatCard(String value, String label, Color valueColor) { - // In React: F9E547 is yellow. On white bg it is low contrast. - // However, the prompt asks to match React UI. - // The React code uses `colors.accent` for XP value which is #F9E547. - // I will stick to it, maybe add a slight shadow or darker shade if it's invisible. - // Actually, for better visibility, I might use a slightly darker yellow/gold for text if needed, - // but the prompt says "Match every visible component exactly". I'll use the hex provided. - - // React code: - //
- - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - children: [ - Text( - value, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: valueColor == const Color(0xFFF9E547) - ? const Color(0xFFEAB308) - : valueColor, // Adjusted yellow to readable gold - ), - ), - const SizedBox(height: 4), - Text( - label, - style: const TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - ], - ), - ); - } - - Widget _buildCourseList() { - if (_courses.isEmpty) { - return const Center( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 48), - child: Column( - children: [ - Icon(LucideIcons.award, size: 48, color: Color(0xFF6A7382)), - SizedBox(height: 12), - Text( - 'No trainings available yet', - style: TextStyle(color: Color(0xFF6A7382)), - ), - ], - ), - ), - ); - } - - return Column( - children: _courses.map((course) { - final bool isCompleted = course['completed']; - final int progressPercent = course['progressPercent']; - - return Container( - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - clipBehavior: Clip.hardEdge, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, // Align to top - children: [ - // Thumbnail area - Container( - width: 96, - height: - 120, // height needs to be sufficient to cover the card content or fixed - // React uses flex with h-24 w-24 (96px). - // But the card might be taller if description is long. - // I'll make it fixed width, and height matching parent via IntrinsicHeight if needed, - // or just fixed height since content is short. - // Let's use a fixed height for consistency or aspect ratio. - color: const Color( - 0xFF0A39DF, - ).withOpacity(0.06), // primary + alpha - child: Center( - child: course['thumbnailUrl'] != null - ? Image.network( - course['thumbnailUrl'], - fit: BoxFit.cover, - ) - : const Icon( - LucideIcons.play, - size: 32, - color: Color(0xFF0A39DF), - ), - ), - ), - - // Content - Expanded( - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - course['title'], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - if (isCompleted) - const Icon( - LucideIcons.checkCircle, - size: 20, - color: Color(0xFF22C55E), - ), // Green-500 - ], - ), - const SizedBox(height: 4), - Text( - course['description'], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 8), - Row( - children: [ - const Icon( - LucideIcons.clock, - size: 12, - color: Color(0xFF6A7382), - ), - const SizedBox(width: 4), - Text( - '${course['durationMinutes']} min', - style: const TextStyle( - fontSize: 12, - color: Color(0xFF6A7382), - ), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 0, - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - border: Border.all( - color: const Color(0xFFF9E547), - ), - ), - child: Text( - '+${course['xpReward']} XP', - style: const TextStyle( - fontSize: 10, - color: Color(0xFF121826), - ), - ), - ), - ], - ), - if (progressPercent > 0 && !isCompleted) ...[ - const SizedBox(height: 8), - ClipRRect( - borderRadius: BorderRadius.circular(2), - child: LinearProgressIndicator( - value: progressPercent / 100, - minHeight: 4, - backgroundColor: const Color(0xFFE3E6E9), - valueColor: const AlwaysStoppedAnimation( - Color(0xFF0A39DF), - ), - ), - ), - ], - ], - ), - ), - ), - ], - ), - ); - }).toList(), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/attire_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/attire_screen.dart deleted file mode 100644 index 9f218dc5..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/attire_screen.dart +++ /dev/null @@ -1,567 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class AttireScreen extends ConsumerStatefulWidget { - const AttireScreen({super.key}); - - @override - ConsumerState createState() => _AttireScreenState(); -} - -class _AttireScreenState extends ConsumerState { - // Mock Data matching React - final List> _attireOptions = [ - { - 'id': 'non_slip_shoes', - 'label': 'Non Slip Shoes', - 'icon': LucideIcons.footprints, - 'imageUrl': 'https://i.ebayimg.com/images/g/8N8AAOSwmkhgalWb/s-l1200.jpg', - }, - { - 'id': 'blue_jeans', - 'label': 'Blue Jeans', - 'icon': LucideIcons.scissors, - 'imageUrl': - 'https://www.gerberchildrenswear.com/cdn/shop/files/Gerber_1-pack-baby-neutral-blue-straight-fit-jeans-evyr-d_image_1.jpg?v=1721762942&width=1920', - }, - { - 'id': 'black_pants', - 'label': 'Black Pants', - 'icon': LucideIcons.user, - 'imageUrl': - 'https://media.gq.com/photos/5d1a2c8185896900081d0462/3:4/w_748%2Cc_limit/GQ-black-pants-stella-3x2.jpg', - }, - { - 'id': 'white_polo', - 'label': 'White Polo', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://images.unsplash.com/photo-1581655353564-df123a1eb820?q=80&w=300&auto=format&fit=crop', - }, - { - 'id': 'black_socks', - 'label': 'Black Socks', - 'icon': LucideIcons.footprints, - 'imageUrl': - 'https://cdn.shopify.com/s/files/1/0472/6493/products/Everyday-Sock-Black-IMG_0408_fb623806-8c31-4627-8816-840fec9c1bde.jpg?v=1681767074&width=1500', - }, - { - 'id': 'catering_shirt', - 'label': 'Catering Shirt', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://images.unsplash.com/photo-1618354691373-d851c5c3a990?q=80&w=300&auto=format&fit=crop', - }, - { - 'id': 'banquette', - 'label': 'Banquette', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://images.unsplash.com/photo-1594938298603-c8148c4dae35?q=80&w=300&auto=format&fit=crop', - }, - { - 'id': 'black_cap', - 'label': 'Black Cap', - 'icon': LucideIcons.hardHat, - 'imageUrl': - 'https://www.stormtech.ca/cdn/shop/products/FPX-2-04000000-FRONT.jpg?v=1736187261&width=2400', - }, - { - 'id': 'chef_coat', - 'label': 'Chef Coat', - 'icon': LucideIcons.chefHat, - 'imageUrl': 'https://cdn.4imprint.ca/prod/extras/144601/515360/700/1.jpg', - }, - { - 'id': 'black_button_up', - 'label': 'Black Button Up', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://cdn-images.farfetch-contents.com/17/05/87/96/17058796_34657384_600.jpg', - }, - { - 'id': 'black_polo', - 'label': 'Black Polo', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTD_67YJX5fnZB5Qy1mATbHhQUVo96CryuMwA&s', - }, - { - 'id': 'all_black_bistro', - 'label': 'All Black Bistro', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://cdnimg.webstaurantstore.com/images/products/large/740190/2526926.jpg', - }, - { - 'id': 'white_button_up', - 'label': 'White Button Up', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTP_Vlx2e44njSqec58u0Qn3qDnWxRK6fYQvg&s', - }, - { - 'id': 'white_black_bistro', - 'label': 'White and Black Bistro', - 'icon': LucideIcons.shirt, - 'imageUrl': - 'https://cdnimg.webstaurantstore.com/images/products/large/740190/2526926.jpg', - }, - ]; - - // Mock mandatory items (e.g. for Server) - final List _mandatoryItems = [ - 'non_slip_shoes', - 'black_pants', - 'white_button_up', - 'black_socks', - ]; - - final List _selectedAttire = []; - final Map _attirePhotos = {}; // id -> url - final Map _uploading = {}; - bool _attestationChecked = false; - - @override - void initState() { - super.initState(); - // Pre-select mandatory - _selectedAttire.addAll(_mandatoryItems); - } - - void _toggleAttire(String id) { - if (_mandatoryItems.contains(id)) return; - setState(() { - if (_selectedAttire.contains(id)) { - _selectedAttire.remove(id); - } else { - _selectedAttire.add(id); - } - }); - } - - void _handlePhotoUpload(String id) async { - setState(() => _uploading[id] = true); - // Simulate upload - await Future.delayed(const Duration(seconds: 1)); - if (mounted) { - setState(() { - _uploading[id] = false; - _attirePhotos[id] = 'mock_url'; // Mocked - if (!_selectedAttire.contains(id)) { - _selectedAttire.add(id); - } - }); - } - } - - @override - Widget build(BuildContext context) { - final allMandatorySelected = _mandatoryItems.every( - (id) => _selectedAttire.contains(id), - ); - final allMandatoryHavePhotos = _mandatoryItems.every( - (id) => _attirePhotos.containsKey(id), - ); - final canSave = - allMandatorySelected && allMandatoryHavePhotos && _attestationChecked; - - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Attire', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - _buildInfoCard(), - const SizedBox(height: 24), - _buildAttireGrid(), - const SizedBox(height: 24), - _buildAttestation(), - const SizedBox(height: 80), - ], - ), - ), - ), - _buildBottomBar( - canSave, - allMandatorySelected, - allMandatoryHavePhotos, - ), - ], - ), - ); - } - - Widget _buildInfoCard() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.08), - borderRadius: BorderRadius.circular(8), - ), - child: const Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(LucideIcons.shirt, color: AppColors.krowBlue, size: 24), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Your Wardrobe', - style: TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14, - color: Color(0xFF121826), - ), - ), - SizedBox(height: 2), - Text( - 'Select the attire items you own. This helps us match you with shifts that fit your wardrobe.', - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildAttireGrid() { - return GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - childAspectRatio: 0.8, // Taller for photo upload button - ), - itemCount: _attireOptions.length, - itemBuilder: (context, index) { - final item = _attireOptions[index]; - final id = item['id'] as String; - final isSelected = _selectedAttire.contains(id); - final isMandatory = _mandatoryItems.contains(id); - final hasPhoto = _attirePhotos.containsKey(id); - final isUploading = _uploading[id] ?? false; - - return Container( - decoration: BoxDecoration( - color: isSelected - ? AppColors.krowBlue.withOpacity(0.1) - : Colors.transparent, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: isSelected ? AppColors.krowBlue : const Color(0xFFE3E6E9), - width: 2, - ), - ), - child: Stack( - children: [ - if (isMandatory) - Positioned( - top: 8, - left: 8, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: Colors.red, - borderRadius: BorderRadius.circular(4), - ), - child: const Text( - 'REQUIRED', - style: TextStyle( - color: Colors.white, - fontSize: 9, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - if (hasPhoto) - Positioned( - top: 8, - right: 8, - child: Container( - width: 20, - height: 20, - decoration: const BoxDecoration( - color: AppColors.krowBlue, - shape: BoxShape.circle, - ), - child: const Center( - child: Icon( - LucideIcons.check, - color: Colors.white, - size: 12, - ), - ), - ), - ), - - Padding( - padding: const EdgeInsets.all(12), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () => _toggleAttire(id), - child: Column( - children: [ - item['imageUrl'] != null - ? Container( - height: 80, - width: 80, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - image: DecorationImage( - image: NetworkImage( - item['imageUrl'] as String, - ), - fit: BoxFit.cover, - ), - ), - ) - : Icon( - item['icon'] as IconData, - size: 48, - color: AppColors.krowCharcoal, - ), - const SizedBox(height: 8), - Text( - item['label'] as String, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ], - ), - ), - const SizedBox(height: 12), - - // Upload Button - InkWell( - onTap: () => _handlePhotoUpload(id), - borderRadius: BorderRadius.circular(8), - child: Container( - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 12, - ), - decoration: BoxDecoration( - color: hasPhoto - ? AppColors.krowBlue.withOpacity(0.05) - : Colors.white, - border: Border.all( - color: hasPhoto - ? AppColors.krowBlue - : AppColors.krowBorder, - ), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (isUploading) - const SizedBox( - width: 12, - height: 12, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ) - else if (hasPhoto) - const Icon( - LucideIcons.check, - size: 12, - color: AppColors.krowBlue, - ) - else - const Icon( - LucideIcons.camera, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Text( - isUploading - ? '...' - : hasPhoto - ? 'Added' - : 'Add Photo', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: hasPhoto - ? AppColors.krowBlue - : AppColors.krowMuted, - ), - ), - ], - ), - ), - ), - - if (hasPhoto) - const Padding( - padding: EdgeInsets.only(top: 4), - child: Text( - '⏳ Pending verification', - style: TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - ), - ), - ], - ), - ), - ], - ), - ); - }, - ); - } - - Widget _buildAttestation() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 24, - height: 24, - child: Checkbox( - value: _attestationChecked, - onChanged: (val) => setState(() => _attestationChecked = val!), - activeColor: AppColors.krowBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - ), - ), - const SizedBox(width: 12), - const Expanded( - child: Text( - 'I certify that I own these items and will wear them to my shifts. I understand that items are pending manager verification at my first shift.', - style: TextStyle(fontSize: 14, color: AppColors.krowCharcoal), - ), - ), - ], - ), - ); - } - - Widget _buildBottomBar( - bool canSave, - bool allMandatorySelected, - bool allMandatoryHavePhotos, - ) { - return Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Color(0xFFE3E6E9))), - ), - child: SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (!canSave) - Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Column( - children: [ - if (!allMandatorySelected) - const Text( - '✓ Select all required items', - style: TextStyle(fontSize: 12, color: Colors.red), - ), - if (!allMandatoryHavePhotos) - const Text( - '✓ Upload photos of required items', - style: TextStyle(fontSize: 12, color: Colors.red), - ), - if (!_attestationChecked) - const Text( - '✓ Accept attestation', - style: TextStyle(fontSize: 12, color: Colors.red), - ), - ], - ), - ), - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: canSave - ? () { - // Save logic - context.pop(); - } - : null, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - disabledBackgroundColor: AppColors.krowMuted, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Text( - 'Save Attire', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart deleted file mode 100644 index efe9b11a..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart +++ /dev/null @@ -1,318 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class EmergencyContactScreen extends ConsumerStatefulWidget { - const EmergencyContactScreen({super.key}); - - @override - ConsumerState createState() => - _EmergencyContactScreenState(); -} - -class _EmergencyContactScreenState - extends ConsumerState { - final List> _contacts = [ - {'name': '', 'phone': '', 'relationship': 'family'}, - ]; - - void _addContact() { - setState(() { - _contacts.add({'name': '', 'phone': '', 'relationship': 'family'}); - }); - } - - void _removeContact(int index) { - if (_contacts.length > 1) { - setState(() { - _contacts.removeAt(index); - }); - } - } - - void _updateContact(int index, String field, dynamic value) { - setState(() { - _contacts[index][field] = value; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Emergency Contact', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - _buildInfoBanner(), - const SizedBox(height: 24), - ..._contacts.asMap().entries.map( - (entry) => _buildContactForm(entry.key, entry.value), - ), - _buildAddButton(), - const SizedBox(height: 80), - ], - ), - ), - ), - _buildSaveButton(), - ], - ), - ); - } - - Widget _buildInfoBanner() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFF9E547).withOpacity(0.2), - borderRadius: BorderRadius.circular(8), - ), - child: const Text( - 'Please provide at least one emergency contact. This information will only be used in case of an emergency during your shifts.', - style: TextStyle(fontSize: 14, color: Color(0xFF121826)), - ), - ); - } - - Widget _buildContactForm(int index, Map contact) { - return Container( - margin: const EdgeInsets.only(bottom: 16), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Contact ${index + 1}', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - if (_contacts.length > 1) - IconButton( - icon: const Icon( - LucideIcons.trash2, - color: Colors.red, - size: 20, - ), - onPressed: () => _removeContact(index), - ), - ], - ), - const SizedBox(height: 16), - _buildLabel('Full Name'), - _buildTextField( - value: contact['name'], - hint: 'Contact name', - icon: LucideIcons.user, - onChanged: (val) => _updateContact(index, 'name', val), - ), - const SizedBox(height: 16), - _buildLabel('Phone Number'), - _buildTextField( - value: contact['phone'], - hint: '+1 (555) 000-0000', - icon: LucideIcons.phone, - onChanged: (val) => _updateContact(index, 'phone', val), - keyboardType: TextInputType.phone, - ), - const SizedBox(height: 16), - _buildLabel('Relationship'), - _buildDropdown( - value: contact['relationship'], - onChanged: (val) => _updateContact(index, 'relationship', val), - ), - ], - ), - ); - } - - Widget _buildLabel(String text) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ); - } - - Widget _buildTextField({ - required String value, - required String hint, - required IconData icon, - required Function(String) onChanged, - TextInputType? keyboardType, - }) { - return TextField( - controller: TextEditingController(text: value) - ..selection = TextSelection.fromPosition( - TextPosition(offset: value.length), - ), - onChanged: onChanged, - keyboardType: keyboardType, - decoration: InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Color(0xFF9CA3AF)), - prefixIcon: Icon(icon, color: const Color(0xFF6A7382), size: 20), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFF0A39DF)), - ), - fillColor: Colors.white, - filled: true, - ), - ); - } - - Widget _buildDropdown({ - required String value, - required Function(String?) onChanged, - }) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(6), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - value: value, - isExpanded: true, - items: const [ - DropdownMenuItem(value: 'family', child: Text('Family Member')), - DropdownMenuItem(value: 'spouse', child: Text('Spouse/Partner')), - DropdownMenuItem(value: 'friend', child: Text('Friend')), - DropdownMenuItem(value: 'other', child: Text('Other')), - ], - onChanged: onChanged, - ), - ), - ); - } - - Widget _buildAddButton() { - return SizedBox( - width: double.infinity, - height: 48, - child: OutlinedButton( - onPressed: _addContact, - style: OutlinedButton.styleFrom( - side: const BorderSide(color: Color(0xFF0A39DF)), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.plus, color: Color(0xFF0A39DF), size: 20), - SizedBox(width: 8), - Text( - 'Add Another Contact', - style: TextStyle( - color: Color(0xFF0A39DF), - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ); - } - - Widget _buildSaveButton() { - return Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Color(0xFFE3E6E9))), - ), - child: SafeArea( - child: SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () { - // Save logic - context.pop(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0A39DF), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.save, color: Colors.white, size: 20), - SizedBox(width: 8), - Text( - 'Save Contacts', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/experience_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/experience_screen.dart deleted file mode 100644 index 23f8869c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/experience_screen.dart +++ /dev/null @@ -1,371 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class ExperienceScreen extends ConsumerStatefulWidget { - const ExperienceScreen({super.key}); - - @override - ConsumerState createState() => _ExperienceScreenState(); -} - -class _ExperienceScreenState extends ConsumerState { - // Mock Data - final List _industryOptions = [ - 'hospitality', - 'food_service', - 'warehouse', - 'events', - 'retail', - 'healthcare', - 'other', - ]; - - final List _skillOptions = [ - 'Food Service', - 'Bartending', - 'Event Setup', - 'Hospitality', - 'Warehouse', - 'Customer Service', - 'Cleaning', - 'Security', - 'Retail', - 'Cooking', - 'Cashier', - 'Server', - 'Barista', - 'Host/Hostess', - 'Busser', - ]; - - List _selectedIndustries = []; - List _selectedSkills = []; - final TextEditingController _customSkillController = TextEditingController(); - - void _toggleIndustry(String industry) { - setState(() { - if (_selectedIndustries.contains(industry)) { - _selectedIndustries.remove(industry); - } else { - _selectedIndustries.add(industry); - } - }); - } - - void _toggleSkill(String skill) { - setState(() { - if (_selectedSkills.contains(skill)) { - _selectedSkills.remove(skill); - } else { - _selectedSkills.add(skill); - } - }); - } - - void _addCustomSkill() { - final skill = _customSkillController.text.trim(); - if (skill.isNotEmpty && !_selectedSkills.contains(skill)) { - setState(() { - _selectedSkills.add(skill); - _customSkillController.clear(); - }); - } - } - - @override - void dispose() { - _customSkillController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Experience & Skills', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildSectionTitle('Industries'), - const Text( - 'Select the industries you have experience in', - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 12), - Wrap( - spacing: 8, - runSpacing: 8, - children: _industryOptions - .map( - (i) => _buildBadge( - i, - _selectedIndustries.contains(i), - () => _toggleIndustry(i), - isIndustry: true, - ), - ) - .toList(), - ), - const SizedBox(height: 24), - _buildSectionTitle('Skills'), - const Text( - 'Select your skills or add custom ones', - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 12), - Wrap( - spacing: 8, - runSpacing: 8, - children: _skillOptions - .map( - (s) => _buildBadge( - s, - _selectedSkills.contains(s), - () => _toggleSkill(s), - ), - ) - .toList(), - ), - const SizedBox(height: 16), - _buildCustomSkillInput(), - const SizedBox(height: 16), - if (_selectedSkills.any((s) => !_skillOptions.contains(s))) - _buildCustomSkillsList(), - const SizedBox(height: 80), - ], - ), - ), - ), - _buildSaveButton(), - ], - ), - ); - } - - Widget _buildSectionTitle(String title) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Text( - title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF121826), - ), - ), - ); - } - - Widget _buildBadge( - String label, - bool isSelected, - VoidCallback onTap, { - bool isIndustry = false, - }) { - final displayLabel = isIndustry - ? label - .replaceAll('_', ' ') - .replaceFirst(label[0], label[0].toUpperCase()) - : label; // Simple capitalize for industry - - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: isSelected ? const Color(0xFF0A39DF) : Colors.transparent, - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: isSelected - ? const Color(0xFF0A39DF) - : const Color(0xFFE3E6E9), - ), - ), - child: Text( - isIndustry - ? (displayLabel[0].toUpperCase() + displayLabel.substring(1)) - : displayLabel, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: isSelected ? Colors.white : const Color(0xFF6A7382), - ), - ), - ), - ); - } - - Widget _buildCustomSkillInput() { - return Row( - children: [ - Expanded( - child: TextField( - controller: _customSkillController, - onSubmitted: (_) => _addCustomSkill(), - decoration: InputDecoration( - hintText: 'Add custom skill...', - hintStyle: const TextStyle(color: Color(0xFF9CA3AF)), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFF0A39DF)), - ), - fillColor: Colors.white, - filled: true, - ), - ), - ), - const SizedBox(width: 8), - InkWell( - onTap: _addCustomSkill, - child: Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: const Color(0xFF0A39DF), - borderRadius: BorderRadius.circular(6), - ), - child: const Center( - child: Icon(LucideIcons.plus, color: Colors.white), - ), - ), - ), - ], - ); - } - - Widget _buildCustomSkillsList() { - final customSkills = _selectedSkills - .where((s) => !_skillOptions.contains(s)) - .toList(); - if (customSkills.isEmpty) return const SizedBox.shrink(); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Custom Skills:', - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 8), - Wrap( - spacing: 8, - runSpacing: 8, - children: customSkills.map((skill) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: const Color(0xFFF9E547), - borderRadius: BorderRadius.circular(20), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - skill, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - const SizedBox(width: 4), - GestureDetector( - onTap: () => _toggleSkill(skill), - child: const Icon( - LucideIcons.x, - size: 14, - color: Color(0xFF121826), - ), - ), - ], - ), - ); - }).toList(), - ), - ], - ); - } - - Widget _buildSaveButton() { - return Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Color(0xFFE3E6E9))), - ), - child: SafeArea( - child: SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () { - // Save logic - context.pop(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0A39DF), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.save, color: Colors.white, size: 20), - SizedBox(width: 8), - Text( - 'Save Experience', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/personal_info_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/personal_info_screen.dart deleted file mode 100644 index 499656d7..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/onboarding/personal_info_screen.dart +++ /dev/null @@ -1,334 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import '../../../../theme.dart'; - -class PersonalInfoScreen extends ConsumerStatefulWidget { - const PersonalInfoScreen({super.key}); - - @override - ConsumerState createState() => _PersonalInfoScreenState(); -} - -class _PersonalInfoScreenState extends ConsumerState { - // Mock User Data - final Map _user = { - 'id': 't8P3fYh4y1cPoZbbVPXUhfQCsDo3', - 'fullName': 'Krower', - 'email': 'worker@krow.com', - 'photoUrl': null, - 'userRole': 'staff', - }; - - final Map _staff= { - 'id': '93673c8f-91aa-405d-8647-f1aac29cc19b', - 'userId': 't8P3fYh4y1cPoZbbVPXUhfQCsDo3', - 'fullName': 'Krower', - 'level': 'Krower I', - 'totalShifts': 0, - 'averageRating': 5.0, - 'onTimeRate': 100, - 'noShowCount': 0, - 'cancellationCount': 0, - 'reliabilityScore': 100, - 'phone': '555-123-4567', // Mock for hasPersonalInfo - 'skills': [], // Mock for hasExperience - 'emergencyContacts': [], // Mock for hasEmergencyContact - 'bio': 'Experienced warehouse staff with a passion for hospitality and a keen eye for detail. Always ready for a new challenge!', - 'preferredLocations': ['Montreal', 'Quebec City'], - 'maxDistanceMiles': 25, - 'industries': [], - 'languages': ['English', 'Spanish'], - 'vendorId': '93678f7v-01aa-505d-9647-g1aac29cc123', - }; - - // Form State - late TextEditingController _phoneController; - late TextEditingController _bioController; - late TextEditingController _languagesController; - late TextEditingController _locationsController; - - @override - void initState() { - super.initState(); - _phoneController = TextEditingController(text: ''); - _bioController = TextEditingController(text: ''); - _languagesController = TextEditingController(text: ''); - _locationsController = TextEditingController(text: ''); - } - - @override - void dispose() { - _phoneController.dispose(); - _bioController.dispose(); - _languagesController.dispose(); - _locationsController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xFFFAFBFC), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.chevronLeft, color: Color(0xFF6A7382)), - onPressed: () => context.pop(), - ), - title: const Text( - 'Personal Info', - style: TextStyle( - color: Color(0xFF121826), - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1.0), - child: Container(color: const Color(0xFFE3E6E9), height: 1.0), - ), - ), - body: Column( - children: [ - Expanded( - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - _buildProfilePhoto(), - const SizedBox(height: 24), - _buildFormFields(), - const SizedBox(height: 80), // Space for bottom button - ], - ), - ), - ), - _buildSaveButton(), - ], - ), - ); - } - - Widget _buildProfilePhoto() { - return Column( - children: [ - Stack( - children: [ - Container( - width: 96, - height: 96, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: const Color(0xFF0A39DF).withOpacity(0.1), - ), - child: _user['photoUrl'] != null - ? ClipOval( - child: Image.network( - _user['photoUrl'], - fit: BoxFit.cover, - ), - ) - : Center( - child: Text( - (_user['fullName'] as String)[0], - style: const TextStyle( - fontSize: 32, - fontWeight: FontWeight.bold, - color: Color(0xFF0A39DF), - ), - ), - ), - ), - Positioned( - bottom: 0, - right: 0, - child: Container( - width: 32, - height: 32, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - border: Border.all(color: const Color(0xFFE3E6E9)), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: const Center( - child: Icon( - LucideIcons.camera, - size: 16, - color: Color(0xFF0A39DF), - ), - ), - ), - ), - ], - ), - const SizedBox(height: 12), - const Text( - 'Tap to change photo', - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - ], - ); - } - - Widget _buildFormFields() { - - _phoneController.text = (_staff['phone'] ?? '') as String; - _bioController.text = (_staff['bio'] ?? '') as String; - - final langs = _staff['languages']; - _languagesController.text =(langs is List) ? langs.join(', ') : (langs?.toString() ?? ''); - - final locs = _staff['preferredLocations']; - _locationsController.text = (locs is List) ? locs.join(', ') : (locs?.toString() ?? ''); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildLabel('Full Name'), - _buildReadOnlyField(_user['fullName']), - const SizedBox(height: 16), - _buildLabel('Email'), - _buildReadOnlyField(_user['email']), - const SizedBox(height: 16), - _buildLabel('Phone Number'), - _buildTextField(_phoneController, '+1 (555) 000-0000'), - const SizedBox(height: 16), - _buildLabel('Bio'), - _buildTextField( - _bioController, - 'Tell clients about yourself...', - maxLines: 4, - ), - const SizedBox(height: 16), - _buildLabel('Languages'), - _buildTextField(_languagesController, 'English, Spanish, French...'), - const SizedBox(height: 16), - _buildLabel('Preferred Locations'), - _buildTextField(_locationsController, 'Downtown, Midtown, Brooklyn...'), - ], - ); - } - - Widget _buildLabel(String text) { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Text( - text, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF121826), - ), - ), - ); - } - - Widget _buildReadOnlyField(String text) { - return Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), - decoration: BoxDecoration( - color: const Color(0xFFF9FAFB), - borderRadius: BorderRadius.circular(6), - border: Border.all(color: const Color(0xFFE3E6E9)), - ), - child: Text( - text, - style: const TextStyle(fontSize: 14, color: Color(0xFF121826)), - ), - ); - } - - Widget _buildTextField( - TextEditingController controller, - String hint, { - int maxLines = 1, - }) { - return TextField( - controller: controller, - maxLines: maxLines, - decoration: InputDecoration( - hintText: hint, - hintStyle: const TextStyle(color: Color(0xFF9CA3AF)), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFFE3E6E9)), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(6), - borderSide: const BorderSide(color: Color(0xFF0A39DF)), - ), - fillColor: Colors.white, - filled: true, - ), - ); - } - - Widget _buildSaveButton() { - return Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Color(0xFFE3E6E9))), - ), - child: SafeArea( - child: SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () { - // Save logic - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Personal info saved (Placeholder)'), - duration: Duration(seconds: 2), - ), - ); - context.pop(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0A39DF), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.save, color: Colors.white, size: 20), - SizedBox(width: 8), - Text( - 'Save Changes', - style: TextStyle( - color: Colors.white, - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/faqs_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/faqs_screen.dart deleted file mode 100644 index 46ef90cb..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/faqs_screen.dart +++ /dev/null @@ -1,319 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../../../theme.dart'; - -class FAQsScreen extends StatefulWidget { - const FAQsScreen({super.key}); - - @override - State createState() => _FAQsScreenState(); -} - -class _FAQsScreenState extends State { - final TextEditingController _searchController = TextEditingController(); - String _searchQuery = ''; - final Map _openItems = {}; - - final List> _faqData = [ - { - 'category': 'Getting Started', - 'questions': [ - { - 'q': 'How do I apply for shifts?', - 'a': - 'Browse available shifts on the Shifts tab and tap "Accept" on any shift that interests you. Once confirmed, you\'ll receive all the details you need.', - }, - { - 'q': 'How do I get paid?', - 'a': - 'Payments are processed weekly via direct deposit to your linked bank account. You can view your earnings in the Payments section.', - }, - { - 'q': 'What if I need to cancel a shift?', - 'a': - 'You can cancel a shift up to 24 hours before it starts without penalty. Late cancellations may affect your reliability score.', - }, - ], - }, - { - 'category': 'Shifts & Work', - 'questions': [ - { - 'q': 'How do I clock in?', - 'a': - 'Use the Clock In feature on the home screen when you arrive at your shift. Make sure location services are enabled for verification.', - }, - { - 'q': 'What should I wear?', - 'a': - 'Check the shift details for dress code requirements. You can manage your wardrobe in the Attire section of your profile.', - }, - { - 'q': 'Who do I contact if I\'m running late?', - 'a': - 'Use the "Running Late" feature in the app to notify the client. You can also message the shift manager directly.', - }, - ], - }, - { - 'category': 'Payments & Earnings', - 'questions': [ - { - 'q': 'When do I get paid?', - 'a': - 'Payments are processed every Friday for shifts completed the previous week. Funds typically arrive within 1-2 business days.', - }, - { - 'q': 'How do I update my bank account?', - 'a': - 'Go to Profile > Finance > Bank Account to add or update your banking information.', - }, - { - 'q': 'Where can I find my tax documents?', - 'a': - 'Tax documents (1099) are available in Profile > Compliance > Tax Documents by January 31st each year.', - }, - ], - }, - ]; - - @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } - - void _toggleItem(String key) { - setState(() { - _openItems[key] = !(_openItems[key] ?? false); - }); - } - - @override - Widget build(BuildContext context) { - // Filter logic - final filteredFaqs = _faqData - .map((cat) { - final questions = (cat['questions'] as List).where((q) { - final question = (q['q'] as String).toLowerCase(); - final answer = (q['a'] as String).toLowerCase(); - final query = _searchQuery.toLowerCase(); - return question.contains(query) || answer.contains(query); - }).toList(); - return {'category': cat['category'], 'questions': questions}; - }) - .where((cat) => (cat['questions'] as List).isNotEmpty) - .toList(); - - return Scaffold( - backgroundColor: AppColors.krowBackground, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: GestureDetector( - onTap: () => context.pop(), - child: const Icon( - LucideIcons.chevronLeft, - color: AppColors.krowMuted, - ), - ), - title: const Text( - "FAQs", - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1), - child: Container(color: AppColors.krowBorder, height: 1), - ), - ), - body: Stack( - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 100), // Space for bottom bar - child: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - // Search - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: TextField( - controller: _searchController, - onChanged: (val) => setState(() => _searchQuery = val), - decoration: const InputDecoration( - hintText: "Search questions...", - hintStyle: TextStyle(color: AppColors.krowMuted), - prefixIcon: Icon( - LucideIcons.search, - color: AppColors.krowMuted, - ), - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 12), - ), - ), - ), - const SizedBox(height: 24), - - // FAQ List - if (filteredFaqs.isEmpty) - const Padding( - padding: EdgeInsets.symmetric(vertical: 48), - child: Column( - children: [ - Icon( - LucideIcons.helpCircle, - size: 48, - color: AppColors.krowMuted, - ), - SizedBox(height: 12), - Text( - "No matching questions found", - style: TextStyle(color: AppColors.krowMuted), - ), - ], - ), - ) - else - ...filteredFaqs.asMap().entries.map((entry) { - final catIndex = entry.key; - final category = entry.value; - final questions = category['questions'] as List; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - category['category'] as String, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - const SizedBox(height: 12), - ...questions.asMap().entries.map((qEntry) { - final qIndex = qEntry.key; - final item = qEntry.value; - final key = "$catIndex-$qIndex"; - final isOpen = _openItems[key] ?? false; - - return Container( - margin: const EdgeInsets.only(bottom: 8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - InkWell( - onTap: () => _toggleItem(key), - borderRadius: BorderRadius.circular(8), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Expanded( - child: Text( - item['q'], - style: const TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - ), - Icon( - isOpen - ? LucideIcons.chevronUp - : LucideIcons.chevronDown, - color: AppColors.krowMuted, - size: 20, - ), - ], - ), - ), - ), - if (isOpen) - Padding( - padding: const EdgeInsets.fromLTRB( - 16, - 0, - 16, - 16, - ), - child: Text( - item['a'], - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - height: 1.5, - ), - ), - ), - ], - ), - ); - }).toList(), - const SizedBox(height: 12), - ], - ); - }).toList(), - ], - ), - ), - ), - Positioned( - left: 0, - right: 0, - bottom: 0, - child: Container( - padding: const EdgeInsets.all(20), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: AppColors.krowBorder)), - ), - child: SafeArea( - top: false, - child: SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: () => context.push('/messages'), - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.messageCircle, size: 20), - SizedBox(width: 8), - Text( - "Contact Support", - style: TextStyle(fontWeight: FontWeight.w600), - ), - ], - ), - ), - ), - ), - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/messages_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/messages_screen.dart deleted file mode 100644 index 40b7d553..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/messages_screen.dart +++ /dev/null @@ -1,558 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../../../theme.dart'; - -class MessagesScreen extends StatefulWidget { - const MessagesScreen({super.key}); - - @override - State createState() => _MessagesScreenState(); -} - -class _MessagesScreenState extends State { - // Mock User - final String _userEmail = 'worker@krow.com'; - - // Mock Data - final List> _conversations = [ - { - 'senderId': 'manager@cafe.com', - 'senderName': 'Sarah Manager', - 'lastMessage': 'See you tomorrow!', - 'lastTime': DateTime.now().subtract(const Duration(hours: 2)), - 'unread': 2, - 'messages': [ - {'content': 'Hi there!', 'senderId': 'manager@cafe.com'}, - { - 'content': 'Are you available for a shift?', - 'senderId': 'manager@cafe.com', - }, - {'content': 'Yes, I am!', 'senderId': 'worker@krow.com'}, - {'content': 'See you tomorrow!', 'senderId': 'manager@cafe.com'}, - ], - }, - { - 'senderId': 'support@krow.com', - 'senderName': 'Krow Support', - 'lastMessage': 'Your payment has been processed.', - 'lastTime': DateTime.now().subtract(const Duration(days: 1)), - 'unread': 0, - 'messages': [ - {'content': 'Welcome to Krow!', 'senderId': 'support@krow.com'}, - { - 'content': 'Your payment has been processed.', - 'senderId': 'support@krow.com', - }, - ], - }, - ]; - - Map? _selectedChat; - final TextEditingController _messageController = TextEditingController(); - - @override - Widget build(BuildContext context) { - if (_selectedChat != null) { - return _buildChatView(); - } - return _buildConversationListView(); - } - - Widget _buildConversationListView() { - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: GestureDetector( - onTap: () => context.pop(), - child: Container( - margin: const EdgeInsets.all(8), - decoration: const BoxDecoration( - color: Color(0xFFF1F5F9), // slate-100 - shape: BoxShape.circle, - ), - alignment: Alignment.center, - child: const Icon( - LucideIcons.arrowLeft, - color: Color(0xFF475569), - size: 20, - ), // slate-600 - ), - ), - title: const Text( - "Messages", - style: TextStyle( - color: Color(0xFF0F172A), // slate-900 - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(60), - child: Padding( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 16), - child: Container( - height: 48, - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), // slate-50 - borderRadius: BorderRadius.circular(12), - ), - child: const TextField( - decoration: InputDecoration( - hintText: "Search conversations...", - hintStyle: TextStyle(color: Color(0xFF94A3B8)), // slate-400 - prefixIcon: Icon( - LucideIcons.search, - color: Color(0xFF94A3B8), - ), // slate-400 - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 12), - ), - ), - ), - ), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Quick Actions - Row( - children: [ - _buildQuickAction( - LucideIcons.alertTriangle, - "Running Late", - const Color(0xFFFEE2E2), - const Color(0xFFDC2626), - ), - const SizedBox(width: 12), - _buildQuickAction( - LucideIcons.messageCircle, - "Chat Support", - const Color(0xFFE0E7FF), - const Color(0xFF0032A0), - ), - const SizedBox(width: 12), - _buildQuickAction( - LucideIcons.users, - "Group Chat", - const Color(0xFFFEF3C7), - const Color(0xFF333F48), - ), - ], - ), - const SizedBox(height: 24), - - // Recent Chats - const Text( - "Recent Chats", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 12), - - if (_conversations.isEmpty) - const Center( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 48), - child: Column( - children: [ - Icon( - LucideIcons.messageCircle, - size: 48, - color: Color(0xFFCBD5E1), - ), // slate-300 - SizedBox(height: 12), - Text( - "No messages yet", - style: TextStyle(color: Color(0xFF64748B)), - ), // slate-500 - ], - ), - ), - ) - else - ..._conversations.map((conv) { - return GestureDetector( - onTap: () => setState(() => _selectedChat = conv), - child: Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFF1F5F9), - ), // slate-100 - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - ), - ], - ), - child: Row( - children: [ - CircleAvatar( - backgroundColor: const Color(0xFFE0E7FF), - radius: 24, - child: Text( - (conv['senderName'] as String)[0], - style: const TextStyle( - color: Color(0xFF0032A0), - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - conv['senderName'], - style: const TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - Text( - _formatDate(conv['lastTime'] as DateTime), - style: const TextStyle( - fontSize: 12, - color: Color(0xFF94A3B8), // slate-400 - ), - ), - ], - ), - const SizedBox(height: 4), - Row( - children: [ - Expanded( - child: Text( - conv['lastMessage'], - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 14, - color: Color(0xFF64748B), // slate-500 - ), - ), - ), - if ((conv['unread'] as int) > 0) - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: const Color(0xFF0032A0), - borderRadius: BorderRadius.circular(10), - ), - child: Text( - "${conv['unread']}", - style: const TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ); - }).toList(), - - const SizedBox(height: 24), - // Krow Support Banner - Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - const Color(0xFF0032A0).withOpacity(0.05), - const Color(0xFFF8E08E).withOpacity(0.2), - ], - ), - borderRadius: BorderRadius.circular(16), - ), - child: Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: const Color(0xFF0032A0).withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - alignment: Alignment.center, - child: const Icon( - LucideIcons.headphones, - color: Color(0xFF0032A0), - ), - ), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Need Help?", - style: TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), - ), - ), - Text( - "Chat with KROW support 24/7", - style: TextStyle( - fontSize: 12, - color: Color(0xFF475569), - ), - ), - ], - ), - ), - const Icon( - LucideIcons.chevronRight, - color: Color(0xFF94A3B8), - ), - ], - ), - ), - ], - ), - ), - ); - } - - Widget _buildQuickAction( - IconData icon, - String label, - Color bgColor, - Color iconColor, - ) { - return Expanded( - child: Container( - height: 100, - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: const Color(0xFFF1F5F9)), // slate-100 - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 2), - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration(color: bgColor, shape: BoxShape.circle), - alignment: Alignment.center, - child: Icon(icon, color: iconColor, size: 20), - ), - const SizedBox(height: 8), - Text( - label, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: Color(0xFF334155), // slate-700 - ), - ), - ], - ), - ), - ); - } - - Widget _buildChatView() { - final messages = _selectedChat!['messages'] as List; - - return Scaffold( - backgroundColor: Colors.white, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: const Icon(LucideIcons.arrowLeft, color: Color(0xFF475569)), - onPressed: () => setState(() => _selectedChat = null), - ), - title: Row( - children: [ - CircleAvatar( - radius: 16, - backgroundColor: const Color(0xFFE0E7FF), - child: Text( - (_selectedChat!['senderName'] as String)[0], - style: const TextStyle( - fontSize: 12, - color: Color(0xFF0032A0), - fontWeight: FontWeight.bold, - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _selectedChat!['senderName'], - style: const TextStyle( - color: Color(0xFF0F172A), - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - const Text( - "Active now", - style: TextStyle(color: Color(0xFF64748B), fontSize: 12), - ), - ], - ), - ], - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1), - child: Container(color: const Color(0xFFF1F5F9), height: 1), - ), - ), - body: Column( - children: [ - Expanded( - child: ListView.builder( - padding: const EdgeInsets.all(20), - itemCount: messages.length, - itemBuilder: (context, index) { - final msg = messages[index]; - final isMe = msg['senderId'] == _userEmail; - return Align( - alignment: isMe - ? Alignment.centerRight - : Alignment.centerLeft, - child: Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 10, - ), - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width * 0.75, - ), - decoration: BoxDecoration( - color: isMe - ? const Color(0xFF0032A0) - : const Color(0xFFF1F5F9), - borderRadius: BorderRadius.only( - topLeft: const Radius.circular(16), - topRight: const Radius.circular(16), - bottomLeft: isMe - ? const Radius.circular(16) - : Radius.zero, - bottomRight: isMe - ? Radius.zero - : const Radius.circular(16), - ), - ), - child: Text( - msg['content'], - style: TextStyle( - color: isMe ? Colors.white : const Color(0xFF0F172A), - fontSize: 14, - ), - ), - ), - ); - }, - ), - ), - Container( - padding: const EdgeInsets.all(16), - decoration: const BoxDecoration( - color: Colors.white, - border: Border(top: BorderSide(color: Color(0xFFF1F5F9))), - ), - child: SafeArea( - top: false, - child: Row( - children: [ - Expanded( - child: Container( - height: 48, - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), - borderRadius: BorderRadius.circular(12), - ), - child: TextField( - controller: _messageController, - decoration: const InputDecoration( - hintText: "Type a message...", - hintStyle: TextStyle(color: Color(0xFF94A3B8)), - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 16), - ), - ), - ), - ), - const SizedBox(width: 8), - GestureDetector( - onTap: () { - if (_messageController.text.isNotEmpty) { - setState(() { - (_selectedChat!['messages'] as List).add({ - 'content': _messageController.text, - 'senderId': _userEmail, - }); - _messageController.clear(); - }); - } - }, - child: Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: const Color(0xFF0032A0), - borderRadius: BorderRadius.circular(12), - ), - alignment: Alignment.center, - child: const Icon( - LucideIcons.send, - color: Colors.white, - size: 20, - ), - ), - ), - ], - ), - ), - ), - ], - ), - ); - } - - String _formatDate(DateTime date) { - return "${date.month}/${date.day}/${date.year}"; - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/privacy_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/privacy_screen.dart deleted file mode 100644 index 89254c18..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile/support/privacy_screen.dart +++ /dev/null @@ -1,267 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../../../theme.dart'; - -class PrivacyScreen extends StatefulWidget { - const PrivacyScreen({super.key}); - - @override - State createState() => _PrivacyScreenState(); -} - -class _PrivacyScreenState extends State { - // Mock Settings State - bool _locationSharing = true; - bool _profileVisibility = true; - bool _pushNotifications = true; - bool _emailNotifications = true; - bool _smsNotifications = false; - bool _twoFactor = false; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: GestureDetector( - onTap: () => context.pop(), - child: const Icon( - LucideIcons.chevronLeft, - color: AppColors.krowMuted, - ), - ), - title: const Text( - "Privacy & Security", - style: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - bottom: PreferredSize( - preferredSize: const Size.fromHeight(1), - child: Container(color: AppColors.krowBorder, height: 1), - ), - ), - body: SingleChildScrollView( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - _buildSection( - title: "Privacy", - icon: LucideIcons.eye, - children: [ - _buildSwitchTile( - title: "Location Sharing", - subtitle: "Share location during shifts", - value: _locationSharing, - onChanged: (val) => setState(() => _locationSharing = val), - ), - _buildDivider(), - _buildSwitchTile( - title: "Profile Visibility", - subtitle: "Let clients see your profile", - value: _profileVisibility, - onChanged: (val) => setState(() => _profileVisibility = val), - ), - ], - ), - const SizedBox(height: 24), - _buildSection( - title: "Notifications", - icon: LucideIcons.bell, - children: [ - _buildSwitchTile( - title: "Push Notifications", - subtitle: "Receive push notifications", - value: _pushNotifications, - onChanged: (val) => setState(() => _pushNotifications = val), - ), - _buildDivider(), - _buildSwitchTile( - title: "Email Notifications", - subtitle: "Receive email updates", - value: _emailNotifications, - onChanged: (val) => setState(() => _emailNotifications = val), - ), - _buildDivider(), - _buildSwitchTile( - title: "SMS Notifications", - subtitle: "Receive text messages", - value: _smsNotifications, - onChanged: (val) => setState(() => _smsNotifications = val), - ), - ], - ), - const SizedBox(height: 24), - _buildSection( - title: "Security", - icon: LucideIcons.lock, - children: [ - _buildSwitchTile( - title: "Two-Factor Authentication", - subtitle: "Add extra security to your account", - value: _twoFactor, - onChanged: (val) => setState(() => _twoFactor = val), - ), - _buildDivider(), - _buildActionTile( - title: "Change Password", - subtitle: "Update your password", - onTap: () {}, - ), - _buildDivider(), - _buildActionTile( - title: "Active Sessions", - subtitle: "Manage logged in devices", - onTap: () {}, - ), - ], - ), - const SizedBox(height: 24), - _buildSection( - title: "Legal", - icon: LucideIcons.shield, - children: [ - _buildActionTile(title: "Terms of Service", onTap: () {}), - _buildDivider(), - _buildActionTile(title: "Privacy Policy", onTap: () {}), - _buildDivider(), - _buildActionTile(title: "Data Request", onTap: () {}), - ], - ), - ], - ), - ), - ); - } - - Widget _buildSection({ - required String title, - required IconData icon, - required List children, - }) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 20, color: AppColors.krowBlue), - const SizedBox(width: 8), - Text( - title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - const SizedBox(height: 12), - Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column(children: children), - ), - ], - ); - } - - Widget _buildSwitchTile({ - required String title, - required String subtitle, - required bool value, - required ValueChanged onChanged, - }) { - return Padding( - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - Text( - subtitle, - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - Switch( - value: value, - onChanged: onChanged, - activeColor: AppColors.krowBlue, - ), - ], - ), - ); - } - - Widget _buildActionTile({ - required String title, - String? subtitle, - required VoidCallback onTap, - }) { - return InkWell( - onTap: onTap, - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.krowCharcoal, - ), - ), - if (subtitle != null) - Text( - subtitle, - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - const Icon( - LucideIcons.chevronRight, - size: 20, - color: AppColors.krowMuted, - ), - ], - ), - ), - ); - } - - Widget _buildDivider() { - return const Divider(height: 1, color: AppColors.krowBorder); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile_screen.dart b/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile_screen.dart deleted file mode 100644 index 6f2456bd..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/worker_profile_screen.dart +++ /dev/null @@ -1,667 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; -import 'worker_profile/support/faqs_screen.dart'; -import 'worker_profile/support/privacy_screen.dart'; -import 'worker_profile/support/messages_screen.dart'; - -class WorkerProfileScreen extends StatefulWidget { - const WorkerProfileScreen({super.key}); - - @override - State createState() => _WorkerProfileScreenState(); -} - -class _WorkerProfileScreenState extends State { - // Mock Data - final Map _user = { - 'id': 't8P3fYh4y1cPoZbbVPXUhfQCsDo3', - 'fullName': 'Krower', - 'email': 'worker@krow.com', - 'photoUrl': null, - 'userRole': 'staff', - }; - - final Map _staff = { - 'id': '93673c8f-91aa-405d-8647-f1aac29cc19b', - 'userId': 't8P3fYh4y1cPoZbbVPXUhfQCsDo3', - 'fullName': 'Krower', - 'level': 'Krower I', - 'totalShifts': 0, - 'averageRating': 5.0, - 'onTimeRate': 100, - 'noShowCount': 0, - 'cancellationCount': 0, - 'reliabilityScore': 100, - 'phone': '555-123-4567', // Mock for hasPersonalInfo - 'skills': [], // Mock for hasExperience - 'emergencyContacts': [], // Mock for hasEmergencyContact - 'bio': - 'Experienced warehouse staff with a passion for hospitality and a keen eye for detail. Always ready for a new challenge!', - 'preferredLocations': ['Montreal', 'Quebec City'], - 'maxDistanceMiles': 25, - 'industries': [], - 'languages': ['English', 'Spanish'], - 'vendorId': '93678f7v-01aa-505d-9647-g1aac29cc123', - }; - - // Mock computed properties - bool get _hasPersonalInfo => _staff['phone'] != null; - bool get _hasEmergencyContact => false; - bool get _hasExperience => (_staff['skills'] as List).isNotEmpty; - bool get _hasAttire => false; - bool get _hasDocuments => true; - bool get _hasCertificates => false; - bool get _hasTaxForms => false; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: AppColors.krowBackground, - body: SingleChildScrollView( - padding: const EdgeInsets.only(bottom: 100), - child: Column( - children: [ - _buildHeader(context), - Transform.translate( - offset: const Offset(0, -24), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - _buildReliabilityStatsCard(), - const SizedBox(height: 24), - _buildReliabilityScoreBar(), - const SizedBox(height: 24), - _buildSectionTitle("Onboarding"), - _buildGrid( - crossAxisCount: 2, - childAspectRatio: 0.7, - children: [ - _buildGridItem( - LucideIcons.user, - "Personal Info", - completed: _hasPersonalInfo, - onTap: () => context.push('/personal-info'), - ), - _buildGridItem( - LucideIcons.phone, - "Emergency Contact", - completed: _hasEmergencyContact, - onTap: () => context.push('/emergency-contact'), - ), - _buildGridItem( - LucideIcons.briefcase, - "Experience", - completed: _hasExperience, - onTap: () => context.push('/experience'), - ), - _buildGridItem( - LucideIcons.shirt, - "Attire", - completed: _hasAttire, - onTap: () => context.push('/attire'), - ), - ], - ), - const SizedBox(height: 24), - _buildSectionTitle("Compliance"), - _buildGrid( - crossAxisCount: 3, - childAspectRatio: 0.9, - children: [ - _buildGridItem( - LucideIcons.fileText, - "Documents", - completed: _hasDocuments, - onTap: () => context.push('/documents'), - ), - _buildGridItem( - LucideIcons.award, - "Certificates", - completed: _hasCertificates, - onTap: () => context.push('/certificates'), - ), - _buildGridItem( - LucideIcons.fileText, - "Tax Forms", - completed: _hasTaxForms, - onTap: () => context.push('/tax-forms'), - ), - ], - ), - const SizedBox(height: 24), - _buildSectionTitle("Level Up"), - _buildGrid( - crossAxisCount: 3, - childAspectRatio: 0.9, - children: [ - _buildGridItem( - LucideIcons.graduationCap, - "Krow University", - onTap: () => context.push('/krow-university'), - ), - _buildGridItem( - LucideIcons.bookOpen, - "Trainings", - onTap: () => context.push('/trainings'), - ), - _buildGridItem( - LucideIcons.award, - "Leaderboard", - onTap: () => context.push('/leaderboard'), - ), - ], - ), - const SizedBox(height: 24), - _buildSectionTitle("Finance"), - _buildGrid( - crossAxisCount: 3, - childAspectRatio: 0.9, - children: [ - _buildGridItem( - LucideIcons.building2, - "Bank Account", - onTap: () => context.push('/bank-account'), - ), - _buildGridItem( - LucideIcons.creditCard, - "Payments", - onTap: () => context.go('/payments'), - ), - _buildGridItem( - LucideIcons.clock, - "Timecard", - onTap: () => context.push('/time-card'), - ), - ], - ), - const SizedBox(height: 24), - _buildSectionTitle("Support"), - _buildGrid( - crossAxisCount: 3, - childAspectRatio: 0.9, - children: [ - _buildGridItem( - LucideIcons.helpCircle, - "FAQs", - onTap: () => context.push('/faqs'), - ), - _buildGridItem( - LucideIcons.shield, - "Privacy & Security", - onTap: () => context.push('/privacy'), - ), - _buildGridItem( - LucideIcons.messageCircle, - "Messages", - onTap: () => context.push('/messages'), - ), - ], - ), - const SizedBox(height: 24), - _buildLogoutButton(), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildHeader(BuildContext context) { - return Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(20, 20, 20, 64), - decoration: const BoxDecoration( - color: AppColors.krowBlue, - borderRadius: BorderRadius.vertical(bottom: Radius.circular(24)), - ), - child: SafeArea( - bottom: false, - child: Column( - children: [ - // Top Bar - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - "Profile", - style: TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - GestureDetector( - onTap: () => context.go('/get-started'), - child: Text( - "SIGN OUT", - style: TextStyle( - color: Colors.white.withOpacity(0.8), - fontSize: 14, - fontWeight: FontWeight.w500, - ), - ), - ), - ], - ), - const SizedBox(height: 32), - // Avatar Section - Stack( - alignment: Alignment.bottomRight, - children: [ - Container( - width: 112, - height: 112, - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - AppColors.krowYellow, - AppColors.krowYellow.withOpacity(0.5), - Colors.white, - ], - ), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.2), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: Colors.white.withOpacity(0.2), - width: 4, - ), - ), - child: CircleAvatar( - backgroundColor: Colors.white, - backgroundImage: _user['photoUrl'] != null - ? NetworkImage(_user['photoUrl']) - : null, - child: _user['photoUrl'] == null - ? Container( - width: double.infinity, - height: double.infinity, - decoration: BoxDecoration( - shape: BoxShape.circle, - gradient: const LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - AppColors.krowYellow, - Color(0xFFFFD700), - ], - ), - ), - alignment: Alignment.center, - child: Text( - (_user['fullName'] as String)[0], - style: const TextStyle( - fontSize: 48, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - ) - : null, - ), - ), - ), - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - border: Border.all(color: AppColors.krowBlue, width: 2), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - ), - ], - ), - child: const Icon( - LucideIcons.camera, - size: 16, - color: AppColors.krowBlue, - ), - ), - ], - ), - const SizedBox(height: 16), - Text( - _user['fullName'] ?? 'Krower', - style: const TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 4), - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), - decoration: BoxDecoration( - color: AppColors.krowYellow.withOpacity(0.2), - borderRadius: BorderRadius.circular(20), - ), - child: Text( - _staff['level'] ?? 'Krower I', - style: const TextStyle( - color: AppColors.krowYellow, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildReliabilityStatsCard() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 4, - offset: const Offset(0, 1), - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _buildStatItem( - LucideIcons.briefcase, - "${_staff['totalShifts']}", - "Shifts", - ), - _buildStatItem( - LucideIcons.star, - "${_staff['averageRating'].toStringAsFixed(1)}", - "Rating", - ), - _buildStatItem( - LucideIcons.clock, - "${_staff['onTimeRate']}%", - "On Time", - ), - _buildStatItem( - LucideIcons.xCircle, - "${_staff['noShowCount']}", - "No Shows", - ), - _buildStatItem( - LucideIcons.ban, - "${_staff['cancellationCount']}", - "Cancel.", - ), - ], - ), - ); - } - - Widget _buildStatItem(IconData icon, String value, String label) { - return Expanded( - child: Column( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - borderRadius: BorderRadius.circular(8), - ), - alignment: Alignment.center, - child: Icon(icon, size: 20, color: AppColors.krowBlue), - ), - const SizedBox(height: 4), - Text( - value, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - label, - style: const TextStyle(fontSize: 10, color: AppColors.krowMuted), - ), - ), - ], - ), - ); - } - - Widget _buildReliabilityScoreBar() { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFE8EEFF), - borderRadius: BorderRadius.circular(12), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - "Reliability Score", - style: TextStyle( - color: AppColors.krowBlue, - fontSize: 14, - fontWeight: FontWeight.w600, - ), - ), - Text( - "${_staff['reliabilityScore']}%", - style: const TextStyle( - color: AppColors.krowBlue, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 8), - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: LinearProgressIndicator( - value: (_staff['reliabilityScore'] as int) / 100, - backgroundColor: Colors.white, - color: AppColors.krowBlue, - minHeight: 8, - ), - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - "Keep your score above 45% to continue picking up shifts.", - style: const TextStyle(color: AppColors.krowMuted, fontSize: 10), - ), - ), - ], - ), - ); - } - - Widget _buildSectionTitle(String title) { - return Container( - width: double.infinity, - padding: const EdgeInsets.only(left: 4), - margin: const EdgeInsets.only(bottom: 12), - child: Text( - title.toUpperCase(), - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 12, - fontWeight: FontWeight.w600, - letterSpacing: 0.5, - ), - ), - ); - } - - Widget _buildGrid({ - required int crossAxisCount, - required List children, - double childAspectRatio = 1.0, - }) { - return Wrap( - spacing: 12, - runSpacing: 12, - children: children.map((child) { - return SizedBox( - width: - (MediaQuery.of(context).size.width - - 40 - - (12 * (crossAxisCount - 1))) / - crossAxisCount, - child: child, - ); - }).toList(), - ); - } - - Widget _buildGridItem( - IconData icon, - String label, { - bool? completed, - VoidCallback? onTap, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - padding: const EdgeInsets.all(6), - child: Stack( - children: [ - Align( - alignment: Alignment.center, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.08), - borderRadius: BorderRadius.circular(12), - ), - alignment: Alignment.center, - child: Icon(icon, color: AppColors.krowBlue, size: 24), - ), - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: Text( - label, - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - color: AppColors.krowCharcoal, - fontSize: 12, - fontWeight: FontWeight.w500, - height: 1.2, - ), - ), - ), - ], - ), - ), - if (completed != null) - Positioned( - top: 8, - right: 8, - child: Container( - width: 16, - height: 16, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: completed - ? AppColors.krowBlue - : const Color(0xFFE8EEFF), - ), - alignment: Alignment.center, - child: completed - ? const Icon(Icons.check, size: 10, color: Colors.white) - : const Text( - "!", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowBlue, - ), - ), - ), - ), - ], - ), - ), - ); - } - - Widget _buildLogoutButton() { - return Container( - width: double.infinity, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => context.go('/get-started'), - borderRadius: BorderRadius.circular(12), - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(LucideIcons.logOut, color: Colors.red, size: 20), - SizedBox(width: 8), - Text( - "Sign Out", - style: TextStyle( - color: Colors.red, - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/services/mock_service.dart b/apps/mobile/prototypes/staff_mobile_application/lib/services/mock_service.dart deleted file mode 100644 index f87b620c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/services/mock_service.dart +++ /dev/null @@ -1,78 +0,0 @@ -import '../models/shift.dart'; - -class MockService { - static final Shift _sampleShift1 = Shift( - id: '1', - title: 'Line Cook', - clientName: 'The Burger Joint', - hourlyRate: 22.50, - location: 'Downtown, NY', - locationAddress: '123 Main St, New York, NY 10001', - date: DateTime.now().toIso8601String(), - startTime: '16:00', - endTime: '22:00', - createdDate: DateTime.now() - .subtract(const Duration(hours: 2)) - .toIso8601String(), - tipsAvailable: true, - mealProvided: true, - managers: [ShiftManager(name: 'John Doe', phone: '+1 555 0101')], - description: 'Help with dinner service. Must be experienced with grill.', - ); - - static final Shift _sampleShift2 = Shift( - id: '2', - title: 'Dishwasher', - clientName: 'Pasta Place', - hourlyRate: 18.00, - location: 'Brooklyn, NY', - locationAddress: '456 Bedford Ave, Brooklyn, NY 11211', - date: DateTime.now().add(const Duration(days: 1)).toIso8601String(), - startTime: '18:00', - endTime: '23:00', - createdDate: DateTime.now() - .subtract(const Duration(hours: 5)) - .toIso8601String(), - tipsAvailable: false, - mealProvided: true, - ); - - static final Shift _sampleShift3 = Shift( - id: '3', - title: 'Bartender', - clientName: 'Rooftop Bar', - hourlyRate: 25.00, - location: 'Manhattan, NY', - locationAddress: '789 5th Ave, New York, NY 10022', - date: DateTime.now().add(const Duration(days: 2)).toIso8601String(), - startTime: '19:00', - endTime: '02:00', - createdDate: DateTime.now() - .subtract(const Duration(hours: 1)) - .toIso8601String(), - tipsAvailable: true, - parkingAvailable: true, - description: 'High volume bar. Mixology experience required.', - ); - - Future> getTodayShifts() async { - await Future.delayed(const Duration(milliseconds: 500)); - return [_sampleShift1]; - } - - Future> getTomorrowShifts() async { - await Future.delayed(const Duration(milliseconds: 500)); - return [_sampleShift2]; - } - - Future> getRecommendedShifts() async { - await Future.delayed(const Duration(milliseconds: 500)); - return [_sampleShift3, _sampleShift1, _sampleShift2]; - } - - Future createWorkerProfile(Map data) async { - await Future.delayed(const Duration(seconds: 1)); - } -} - -final mockService = MockService(); diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/theme.dart b/apps/mobile/prototypes/staff_mobile_application/lib/theme.dart deleted file mode 100644 index 2e5291b1..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/theme.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:google_fonts/google_fonts.dart'; - -class AppColors { - static const Color krowBlue = Color(0xFF0A39DF); - static const Color krowYellow = Color(0xFFFFED4A); - static const Color krowCharcoal = Color(0xFF121826); - static const Color krowMuted = Color(0xFF6A7382); - static const Color krowBorder = Color(0xFFE3E6E9); - static const Color krowBackground = Color(0xFFFAFBFC); - - static const Color white = Colors.white; - static const Color black = Colors.black; -} - -class AppTheme { - static ThemeData get lightTheme { - return ThemeData( - useMaterial3: true, - scaffoldBackgroundColor: AppColors.krowBackground, - colorScheme: ColorScheme.fromSeed( - seedColor: AppColors.krowBlue, - primary: AppColors.krowBlue, - secondary: AppColors.krowYellow, - surface: AppColors.white, - background: AppColors.krowBackground, - ), - textTheme: GoogleFonts.instrumentSansTextTheme().apply( - bodyColor: AppColors.krowCharcoal, - displayColor: AppColors.krowCharcoal, - ), - appBarTheme: const AppBarTheme( - backgroundColor: AppColors.krowBackground, - elevation: 0, - iconTheme: IconThemeData(color: AppColors.krowCharcoal), - titleTextStyle: TextStyle( - color: AppColors.krowCharcoal, - fontSize: 18, - fontWeight: FontWeight.w600, - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/attendance_card.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/attendance_card.dart deleted file mode 100644 index 6d150f2f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/attendance_card.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -enum AttendanceType { checkin, checkout, breaks, days } - -class AttendanceCard extends StatelessWidget { - final AttendanceType type; - final String title; - final String value; - final String subtitle; - final String? scheduledTime; - - const AttendanceCard({ - super.key, - required this.type, - required this.title, - required this.value, - required this.subtitle, - this.scheduledTime, - }); - - @override - Widget build(BuildContext context) { - final styles = _getStyles(type); - - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: styles.bgColor, - borderRadius: BorderRadius.circular(12), - ), - child: Icon(styles.icon, size: 16, color: styles.iconColor), - ), - const SizedBox(height: 12), - Text( - title, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - const SizedBox(height: 4), - Text( - value, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - ), - ), - if (scheduledTime != null) ...[ - const SizedBox(height: 2), - Text( - "Scheduled: $scheduledTime", - style: const TextStyle( - fontSize: 10, - color: Color(0xFF94A3B8), // slate-400 - ), - ), - ], - const SizedBox(height: 2), - Text( - subtitle, - style: const TextStyle(fontSize: 12, color: Color(0xFF0032A0)), - ), - ], - ), - ); - } - - _AttendanceStyle _getStyles(AttendanceType type) { - switch (type) { - case AttendanceType.checkin: - return _AttendanceStyle( - icon: LucideIcons.logIn, - bgColor: const Color(0xFF0032A0).withOpacity(0.1), - iconColor: const Color(0xFF0032A0), - ); - case AttendanceType.checkout: - return _AttendanceStyle( - icon: LucideIcons.logOut, - bgColor: const Color(0xFF333F48).withOpacity(0.1), - iconColor: const Color(0xFF333F48), - ); - case AttendanceType.breaks: - return _AttendanceStyle( - icon: LucideIcons.coffee, - bgColor: const Color(0xFFF8E08E).withOpacity(0.3), - iconColor: const Color(0xFF333F48), - ); - case AttendanceType.days: - return _AttendanceStyle( - icon: LucideIcons.calendar, - bgColor: const Color(0xFFF7E600).withOpacity(0.2), - iconColor: const Color(0xFF333F48), - ); - } - } -} - -class _AttendanceStyle { - final IconData icon; - final Color bgColor; - final Color iconColor; - - _AttendanceStyle({ - required this.icon, - required this.bgColor, - required this.iconColor, - }); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/commute_tracker.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/commute_tracker.dart deleted file mode 100644 index 96dc225c..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/commute_tracker.dart +++ /dev/null @@ -1,542 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; -import '../../models/shift.dart'; - -enum CommuteMode { - lockedNoShift, - needsConsent, - preShiftCommuteAllowed, - commuteModeActive, - arrivedCanClockIn, -} - -class CommuteTracker extends StatefulWidget { - final Shift? shift; - final Function(CommuteMode)? onModeChange; - final bool hasLocationConsent; - final bool isCommuteModeOn; - final double? distanceMeters; - final int? etaMinutes; - - const CommuteTracker({ - super.key, - this.shift, - this.onModeChange, - this.hasLocationConsent = false, - this.isCommuteModeOn = false, - this.distanceMeters, - this.etaMinutes, - }); - - @override - State createState() => _CommuteTrackerState(); -} - -class _CommuteTrackerState extends State { - bool _localHasConsent = false; - bool _localIsCommuteOn = false; - - @override - void initState() { - super.initState(); - _localHasConsent = widget.hasLocationConsent; - _localIsCommuteOn = widget.isCommuteModeOn; - } - - CommuteMode _getAppMode() { - if (widget.shift == null) return CommuteMode.lockedNoShift; - - // For demo purposes, check if we're within 24 hours of shift - final now = DateTime.now(); - final shiftStart = DateTime.parse( - '${widget.shift!.date} ${widget.shift!.startTime}', - ); - final hoursUntilShift = shiftStart.difference(now).inHours; - final inCommuteWindow = hoursUntilShift <= 24 && hoursUntilShift >= 0; - - if (_localIsCommuteOn) { - // Check if arrived (mock: if distance < 200m) - if (widget.distanceMeters != null && widget.distanceMeters! <= 200) { - return CommuteMode.arrivedCanClockIn; - } - return CommuteMode.commuteModeActive; - } - - if (inCommuteWindow) { - return _localHasConsent - ? CommuteMode.preShiftCommuteAllowed - : CommuteMode.needsConsent; - } - - return CommuteMode.lockedNoShift; - } - - String _formatDistance(double meters) { - final miles = meters / 1609.34; - return miles < 0.1 - ? '${meters.round()} m' - : '${miles.toStringAsFixed(1)} mi'; - } - - int _getMinutesUntilShift() { - if (widget.shift == null) return 0; - final now = DateTime.now(); - final shiftStart = DateTime.parse( - '${widget.shift!.date} ${widget.shift!.startTime}', - ); - return shiftStart.difference(now).inMinutes; - } - - @override - Widget build(BuildContext context) { - final mode = _getAppMode(); - - // Notify parent of mode change - WidgetsBinding.instance.addPostFrameCallback((_) { - widget.onModeChange?.call(mode); - }); - - switch (mode) { - case CommuteMode.lockedNoShift: - return const SizedBox.shrink(); - - case CommuteMode.needsConsent: - return _buildConsentCard(); - - case CommuteMode.preShiftCommuteAllowed: - return _buildPreShiftCard(); - - case CommuteMode.commuteModeActive: - return _buildActiveCommuteScreen(); - - case CommuteMode.arrivedCanClockIn: - return _buildArrivedCard(); - } - } - - Widget _buildConsentCard() { - return Container( - margin: const EdgeInsets.only(bottom: 20), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - gradient: const LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFFEFF6FF), // blue-50 - Color(0xFFECFEFF), // cyan-50 - ], - ), - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 32, - height: 32, - decoration: const BoxDecoration( - color: Color(0xFF2563EB), // blue-600 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.mapPin, - size: 16, - color: Colors.white, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Enable Commute Tracking?', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 4), - Text( - 'Share location 1hr before shift so your manager can see you\'re on the way.', - style: TextStyle( - fontSize: 12, - color: Color(0xFF475569), // slate-600 - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - Row( - children: [ - Expanded( - child: OutlinedButton( - onPressed: () { - setState(() => _localHasConsent = false); - }, - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 8), - side: const BorderSide(color: Color(0xFFE2E8F0)), - ), - child: const Text('Not Now', style: TextStyle(fontSize: 12)), - ), - ), - const SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: () { - setState(() => _localHasConsent = true); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF2563EB), // blue-600 - padding: const EdgeInsets.symmetric(vertical: 8), - ), - child: const Text( - 'Enable', - style: TextStyle(fontSize: 12, color: Colors.white), - ), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildPreShiftCard() { - return Container( - margin: const EdgeInsets.only(bottom: 20), - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Row( - children: [ - Container( - width: 32, - height: 32, - decoration: const BoxDecoration( - color: Color(0xFFF1F5F9), // slate-100 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.navigation, - size: 16, - color: Color(0xFF475569), // slate-600 - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Text( - 'On My Way', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(width: 8), - Row( - children: [ - const Icon( - LucideIcons.clock, - size: 12, - color: Color(0xFF64748B), // slate-500 - ), - const SizedBox(width: 2), - Text( - 'Shift starts in ${_getMinutesUntilShift()} min', - style: const TextStyle( - fontSize: 11, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ], - ), - const Text( - 'Track arrival', - style: TextStyle( - fontSize: 10, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ), - Switch( - value: _localIsCommuteOn, - onChanged: (value) { - setState(() => _localIsCommuteOn = value); - }, - activeColor: AppColors.krowBlue, - ), - ], - ), - ); - } - - Widget _buildActiveCommuteScreen() { - return Container( - height: MediaQuery.of(context).size.height, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFF2563EB), // blue-600 - Color(0xFF0891B2), // cyan-600 - ], - ), - ), - child: SafeArea( - child: Column( - children: [ - Expanded( - child: Center( - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TweenAnimationBuilder( - tween: Tween(begin: 1.0, end: 1.1), - duration: const Duration(seconds: 1), - curve: Curves.easeInOut, - builder: (context, double scale, child) { - return Transform.scale( - scale: scale, - child: Container( - width: 96, - height: 96, - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.navigation, - size: 48, - color: Colors.white, - ), - ), - ); - }, - onEnd: () { - // Restart animation - setState(() {}); - }, - ), - const SizedBox(height: 24), - const Text( - 'On My Way', - style: TextStyle( - fontSize: 32, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - const SizedBox(height: 8), - Text( - 'Your manager can see you\'re heading to the site', - style: TextStyle( - fontSize: 14, - color: Colors.blue.shade100, - ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 32), - if (widget.distanceMeters != null) ...[ - Container( - width: double.infinity, - constraints: const BoxConstraints(maxWidth: 300), - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: Colors.white.withOpacity(0.2), - ), - ), - child: Column( - children: [ - Text( - 'Distance to Site', - style: TextStyle( - fontSize: 14, - color: Colors.blue.shade100, - ), - ), - const SizedBox(height: 4), - Text( - _formatDistance(widget.distanceMeters!), - style: const TextStyle( - fontSize: 36, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - if (widget.etaMinutes != null) ...[ - const SizedBox(height: 12), - Container( - width: double.infinity, - constraints: const BoxConstraints(maxWidth: 300), - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: Colors.white.withOpacity(0.2), - ), - ), - child: Column( - children: [ - Text( - 'Estimated Arrival', - style: TextStyle( - fontSize: 14, - color: Colors.blue.shade100, - ), - ), - const SizedBox(height: 4), - Text( - '${widget.etaMinutes} min', - style: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - ], - ], - const SizedBox(height: 32), - Text( - 'Most app features are locked while commute mode is on. You\'ll be able to clock in once you arrive.', - style: TextStyle( - fontSize: 12, - color: Colors.blue.shade100, - ), - textAlign: TextAlign.center, - ), - ], - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(20), - child: OutlinedButton( - onPressed: () { - setState(() => _localIsCommuteOn = false); - }, - style: OutlinedButton.styleFrom( - foregroundColor: Colors.white, - side: BorderSide(color: Colors.white.withOpacity(0.3)), - padding: const EdgeInsets.symmetric(vertical: 16), - minimumSize: const Size(double.infinity, 48), - ), - child: const Text('Turn Off Commute Mode'), - ), - ), - ], - ), - ), - ); - } - - Widget _buildArrivedCard() { - return Container( - margin: const EdgeInsets.only(bottom: 20), - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - gradient: const LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - Color(0xFFECFDF5), // emerald-50 - Color(0xFFD1FAE5), // green-50 - ], - ), - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - Container( - width: 64, - height: 64, - decoration: const BoxDecoration( - color: Color(0xFF10B981), // emerald-500 - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.checkCircle, - size: 32, - color: Colors.white, - ), - ), - const SizedBox(height: 16), - const Text( - 'You\'ve Arrived! 🎉', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 8), - const Text( - 'You\'re at the shift location. Ready to clock in?', - style: TextStyle( - fontSize: 14, - color: Color(0xFF475569), // slate-600 - ), - textAlign: TextAlign.center, - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/date_selector.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/date_selector.dart deleted file mode 100644 index 320ba176..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/date_selector.dart +++ /dev/null @@ -1,114 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; - -class DateSelector extends StatelessWidget { - final DateTime selectedDate; - final ValueChanged onSelect; - final List shiftDates; - - const DateSelector({ - super.key, - required this.selectedDate, - required this.onSelect, - this.shiftDates = const [], - }); - - @override - Widget build(BuildContext context) { - final today = DateTime.now(); - final dates = List.generate(7, (index) { - return today.add(Duration(days: index - 3)); - }); - - return SizedBox( - height: 80, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: dates.map((date) { - final isSelected = _isSameDay(date, selectedDate); - final isToday = _isSameDay(date, today); - final hasShift = shiftDates.contains(_formatDateIso(date)); - - return Expanded( - child: GestureDetector( - onTap: () => onSelect(date), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - margin: const EdgeInsets.symmetric(horizontal: 4), - decoration: BoxDecoration( - color: isSelected ? const Color(0xFF0032A0) : Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: isSelected - ? [ - BoxShadow( - color: const Color(0xFF0032A0).withOpacity(0.3), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ] - : [], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - DateFormat('d').format(date), - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: isSelected - ? Colors.white - : const Color(0xFF0F172A), - ), - ), - const SizedBox(height: 2), - Text( - DateFormat('E').format(date), - style: TextStyle( - fontSize: 12, - color: isSelected - ? Colors.white.withOpacity(0.8) - : const Color(0xFF94A3B8), - ), - ), - const SizedBox(height: 4), - if (hasShift) - Container( - width: 6, - height: 6, - decoration: BoxDecoration( - color: isSelected - ? Colors.white - : const Color(0xFF0032A0), - shape: BoxShape.circle, - ), - ) - else if (isToday && !isSelected) - Container( - width: 6, - height: 6, - decoration: BoxDecoration( - color: Colors.grey.shade300, - shape: BoxShape.circle, - ), - ) - else - const SizedBox(height: 6), - ], - ), - ), - ), - ); - }).toList(), - ), - ); - } - - bool _isSameDay(DateTime a, DateTime b) { - return a.year == b.year && a.month == b.month && a.day == b.day; - } - - String _formatDateIso(DateTime date) { - return DateFormat('yyyy-MM-dd').format(date); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/lunch_break_modal.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/lunch_break_modal.dart deleted file mode 100644 index 99a59bd9..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/lunch_break_modal.dart +++ /dev/null @@ -1,518 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class LunchBreakDialog extends StatefulWidget { - final VoidCallback onComplete; - - const LunchBreakDialog({super.key, required this.onComplete}); - - @override - State createState() => _LunchBreakDialogState(); -} - -class _LunchBreakDialogState extends State { - int _step = 1; - bool? _tookLunch; - String? _breakStart = '12:00pm'; - String? _breakEnd = '12:30pm'; - String? _noLunchReason; - String _additionalNotes = ''; - - final List _timeOptions = _generateTimeOptions(); - final List _noLunchReasons = [ - 'Unpredictable Workflows', - 'Poor Time Management', - 'Lack of coverage or short Staff', - 'No Lunch Area', - 'Other (Please specify)', - ]; - - static List _generateTimeOptions() { - List options = []; - for (int h = 0; h < 24; h++) { - for (int m = 0; m < 60; m += 15) { - final hour = h % 12 == 0 ? 12 : h % 12; - final ampm = h < 12 ? 'am' : 'pm'; - final timeStr = '$hour:${m.toString().padLeft(2, '0')}$ampm'; - options.add(timeStr); - } - } - return options; - } - - @override - Widget build(BuildContext context) { - return Dialog( - backgroundColor: Colors.white, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: _buildCurrentStep(), - ), - ); - } - - Widget _buildCurrentStep() { - switch (_step) { - case 1: - return _buildStep1(); - case 2: - return _buildStep2(); - case 102: // 2b: No lunch reason - return _buildStep2b(); - case 3: - return _buildStep3(); - case 4: - return _buildStep4(); - default: - return const SizedBox.shrink(); - } - } - - Widget _buildStep1() { - return Padding( - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - color: Colors.grey.shade100, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.coffee, - size: 40, - color: Color(0xFF6A7382), - ), - ), - const SizedBox(height: 24), - const Text( - "Did You Take\na Lunch?", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 8), - const Text( - "Taking regular breaks helps you stay productive and focused. Did you take a break during your shift?", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () { - setState(() { - _tookLunch = true; - _step = 2; - }); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF121826), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Yes, I Took a Lunch"), - ), - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - height: 56, - child: OutlinedButton( - onPressed: () { - setState(() { - _tookLunch = false; - _step = 102; // 2b - }); - }, - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF121826), - side: const BorderSide(color: Color(0xFFE3E6E9)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("No, I Didn't take a Lunch"), - ), - ), - ], - ), - ); - } - - Widget _buildStep2() { - return Padding( - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - color: Colors.grey.shade100, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.coffee, - size: 40, - color: Color(0xFF6A7382), - ), - ), - const SizedBox(height: 24), - const Text( - "Did You\nTake a Lunch?", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 8), - const Text( - "Select your break time.", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 24), - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "BREAK START TIME", - style: TextStyle(fontSize: 10, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 8), - _buildDropdown( - _breakStart, - (val) => setState(() => _breakStart = val), - ), - ], - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "BREAK END TIME", - style: TextStyle(fontSize: 10, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 8), - _buildDropdown( - _breakEnd, - (val) => setState(() => _breakEnd = val), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () => setState(() => _step = 3), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF121826), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Submit Lunch Time"), - ), - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - height: 56, - child: OutlinedButton( - onPressed: () => setState(() => _step = 1), - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF121826), - side: const BorderSide(color: Color(0xFFE3E6E9)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Cancel"), - ), - ), - ], - ), - ); - } - - Widget _buildStep2b() { - return Padding( - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - color: Colors.red.shade50, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.coffee, - size: 40, - color: Color(0xFFF87171), - ), - ), - const SizedBox(height: 24), - const Text( - "Help Us Understand:\nWhat Kept You From\nTaking a Lunch?", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 24), - DropdownButtonFormField( - value: _noLunchReason, - hint: const Text("Select reason from a list"), - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - ), - contentPadding: const EdgeInsets.symmetric(horizontal: 16), - ), - items: _noLunchReasons - .map( - (r) => DropdownMenuItem( - value: r, - child: Text(r, style: const TextStyle(fontSize: 12)), - ), - ) - .toList(), - onChanged: (val) => setState(() => _noLunchReason = val), - ), - const SizedBox(height: 16), - TextField( - maxLines: 4, - onChanged: (val) => setState(() => _additionalNotes = val), - decoration: InputDecoration( - hintText: "Enter your main text here...", - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - const SizedBox(height: 4), - Align( - alignment: Alignment.centerRight, - child: Text( - "${_additionalNotes.length}/300", - style: const TextStyle(fontSize: 10, color: Colors.grey), - ), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: _noLunchReason == null - ? null - : () => setState(() => _step = 4), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF121826), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Submit Reason"), - ), - ), - const SizedBox(height: 12), - SizedBox( - width: double.infinity, - height: 56, - child: OutlinedButton( - onPressed: () => setState(() => _step = 1), - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFF121826), - side: const BorderSide(color: Color(0xFFE3E6E9)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Cancel"), - ), - ), - ], - ), - ); - } - - Widget _buildStep3() { - return Padding( - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - color: const Color(0xFF10B981).withOpacity(0.1), - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.check, - size: 40, - color: Color(0xFF10B981), - ), - ), - const SizedBox(height: 24), - const Text( - "Congratulations,\nShift Completed!", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 8), - const Text( - "Your break has been logged and added to your timeline. Keep up the good work!", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 14, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () { - Navigator.of(context).pop(); - widget.onComplete(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF121826), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Back to Shift"), - ), - ), - ], - ), - ); - } - - Widget _buildStep4() { - return Padding( - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - width: 80, - height: 80, - decoration: BoxDecoration( - color: Colors.red.shade50, - shape: BoxShape.circle, - ), - child: const Icon( - LucideIcons.alertTriangle, - size: 40, - color: Color(0xFFF87171), - ), - ), - const SizedBox(height: 24), - const Text( - "Your Selection\nis under review", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 8), - const Text( - "Labor Code § 512 requires California employers to give unpaid lunch breaks...", - textAlign: TextAlign.center, - style: TextStyle(fontSize: 12, color: Color(0xFF6A7382)), - ), - const SizedBox(height: 16), - const Text( - "Once resolved you will be notify.\nNo further Action", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xFF121826), - ), - ), - const SizedBox(height: 32), - SizedBox( - width: double.infinity, - height: 56, - child: ElevatedButton( - onPressed: () { - Navigator.of(context).pop(); - widget.onComplete(); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF121826), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(28), - ), - ), - child: const Text("Continue"), - ), - ), - ], - ), - ); - } - - Widget _buildDropdown(String? value, ValueChanged onChanged) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12), - decoration: BoxDecoration( - border: Border.all(color: const Color(0xFFE3E6E9)), - borderRadius: BorderRadius.circular(12), - ), - child: DropdownButtonHideUnderline( - child: DropdownButton( - value: value, - isExpanded: true, - items: _timeOptions - .map((t) => DropdownMenuItem(value: t, child: Text(t))) - .toList(), - onChanged: onChanged, - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/swipe_to_check_in.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/swipe_to_check_in.dart deleted file mode 100644 index ffd960fb..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/clock_in/swipe_to_check_in.dart +++ /dev/null @@ -1,224 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class SwipeToCheckIn extends StatefulWidget { - final VoidCallback? onCheckIn; - final VoidCallback? onCheckOut; - final bool isLoading; - final String mode; // 'swipe' or 'nfc' - final bool isCheckedIn; - - const SwipeToCheckIn({ - super.key, - this.onCheckIn, - this.onCheckOut, - this.isLoading = false, - this.mode = 'swipe', - this.isCheckedIn = false, - }); - - @override - State createState() => _SwipeToCheckInState(); -} - -class _SwipeToCheckInState extends State - with SingleTickerProviderStateMixin { - double _dragValue = 0.0; - final double _maxWidth = 300.0; // Estimate, will get from LayoutBuilder - final double _handleSize = 48.0; - bool _isComplete = false; - - @override - void didUpdateWidget(SwipeToCheckIn oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.isCheckedIn != oldWidget.isCheckedIn) { - setState(() { - _isComplete = false; - _dragValue = 0.0; - }); - } - } - - void _onDragUpdate(DragUpdateDetails details, double maxWidth) { - if (_isComplete || widget.isLoading) return; - setState(() { - _dragValue = (_dragValue + details.delta.dx).clamp( - 0.0, - maxWidth - _handleSize - 8, - ); - }); - } - - void _onDragEnd(DragEndDetails details, double maxWidth) { - if (_isComplete || widget.isLoading) return; - final threshold = (maxWidth - _handleSize - 8) * 0.8; - if (_dragValue > threshold) { - setState(() { - _dragValue = maxWidth - _handleSize - 8; - _isComplete = true; - }); - Future.delayed(const Duration(milliseconds: 300), () { - if (widget.isCheckedIn) { - widget.onCheckOut?.call(); - } else { - widget.onCheckIn?.call(); - } - }); - } else { - setState(() { - _dragValue = 0.0; - }); - } - } - - @override - Widget build(BuildContext context) { - final baseColor = widget.isCheckedIn - ? const Color(0xFF10B981) - : const Color(0xFF0032A0); - - if (widget.mode == 'nfc') { - return GestureDetector( - onTap: () { - if (widget.isLoading) return; - // Simulate completion for NFC tap - Future.delayed(const Duration(milliseconds: 300), () { - if (widget.isCheckedIn) { - widget.onCheckOut?.call(); - } else { - widget.onCheckIn?.call(); - } - }); - }, - child: Container( - height: 56, - decoration: BoxDecoration( - color: baseColor, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: baseColor.withOpacity(0.4), - blurRadius: 25, - offset: const Offset(0, 10), - spreadRadius: -5, - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(LucideIcons.wifi, color: Colors.white), - const SizedBox(width: 12), - Text( - widget.isLoading - ? (widget.isCheckedIn - ? "Checking out..." - : "Checking in...") - : (widget.isCheckedIn ? "NFC Check Out" : "NFC Check In"), - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - ], - ), - ), - ); - } - - return LayoutBuilder( - builder: (context, constraints) { - final maxWidth = constraints.maxWidth; - final maxDrag = maxWidth - _handleSize - 8; - - // Calculate background color based on drag - final progress = _dragValue / maxDrag; - final startColor = widget.isCheckedIn - ? const Color(0xFF10B981) - : const Color(0xFF0032A0); - final endColor = widget.isCheckedIn - ? const Color(0xFF0032A0) - : const Color(0xFF10B981); - final currentColor = - Color.lerp(startColor, endColor, progress) ?? startColor; - - return Container( - height: 56, - decoration: BoxDecoration( - color: currentColor, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Stack( - children: [ - Center( - child: Opacity( - opacity: 1.0 - progress, - child: Text( - widget.isCheckedIn - ? "Swipe to Check Out" - : "Swipe to Check In", - style: TextStyle( - color: Colors.white.withOpacity(0.8), - fontWeight: FontWeight.w600, - fontSize: 18, - ), - ), - ), - ), - if (_isComplete) - Center( - child: Text( - widget.isCheckedIn ? "Check Out!" : "Check In!", - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 18, - ), - ), - ), - Positioned( - left: 4 + _dragValue, - top: 4, - child: GestureDetector( - onHorizontalDragUpdate: (d) => _onDragUpdate(d, maxWidth), - onHorizontalDragEnd: (d) => _onDragEnd(d, maxWidth), - child: Container( - width: _handleSize, - height: _handleSize, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Center( - child: Icon( - _isComplete - ? LucideIcons.check - : LucideIcons.arrowRight, - color: startColor, - ), - ), - ), - ), - ), - ], - ), - ); - }, - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/payment_history_item.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/payment_history_item.dart deleted file mode 100644 index 9c49df1e..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/payment_history_item.dart +++ /dev/null @@ -1,209 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class PaymentHistoryItem extends StatelessWidget { - final double amount; - final String title; - final String location; - final String address; - final String date; - final String workedTime; - final int hours; - final double rate; - final String status; - - const PaymentHistoryItem({ - super.key, - required this.amount, - required this.title, - required this.location, - required this.address, - required this.date, - required this.workedTime, - required this.hours, - required this.rate, - required this.status, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Status Badge - Row( - children: [ - Container( - width: 6, - height: 6, - decoration: const BoxDecoration( - color: Color(0xFF3B82F6), // blue-500 - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 6), - const Text( - "PAID", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w700, - color: Color(0xFF2563EB), // blue-600 - letterSpacing: 0.5, - ), - ), - ], - ), - const SizedBox(height: 12), - - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Icon - Container( - width: 44, - height: 44, - decoration: BoxDecoration( - color: const Color(0xFFF1F5F9), // slate-100 - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - LucideIcons.dollarSign, - color: Color(0xFF334155), // slate-700 - size: 24, - ), - ), - const SizedBox(width: 12), - - // Content - Expanded( - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - Text( - location, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF475569), // slate-600 - ), - ), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - "\$${amount.toStringAsFixed(0)}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - ), - ), - Text( - "\$${rate.toStringAsFixed(0)}/hr · ${hours}h", - style: const TextStyle( - fontSize: 10, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - ], - ), - const SizedBox(height: 8), - - // Date and Time - Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 12, - color: Color(0xFF64748B), - ), - const SizedBox(width: 8), - Text( - date, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - ), - const SizedBox(width: 8), - const Icon( - LucideIcons.clock, - size: 12, - color: Color(0xFF64748B), - ), - const SizedBox(width: 8), - Text( - workedTime, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - ), - ], - ), - const SizedBox(height: 4), - - // Address - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: Color(0xFF64748B), - ), - const SizedBox(width: 8), - Expanded( - child: Text( - address, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ], - ), - ), - ], - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/payment_stats_card.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/payment_stats_card.dart deleted file mode 100644 index aad2cf9b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/payment_stats_card.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class PaymentStatsCard extends StatelessWidget { - final IconData icon; - final Color iconColor; - final String label; - final String amount; - - const PaymentStatsCard({ - super.key, - required this.icon, - required this.iconColor, - required this.label, - required this.amount, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(icon, size: 16, color: iconColor), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - ), - ], - ), - const SizedBox(height: 8), - Text( - amount, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/pending_pay_card.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/pending_pay_card.dart deleted file mode 100644 index 3ca7c602..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/payments/pending_pay_card.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; - -class PendingPayCard extends StatelessWidget { - final double amount; - final VoidCallback onCashOut; - - const PendingPayCard({ - super.key, - required this.amount, - required this.onCashOut, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(14), - decoration: BoxDecoration( - gradient: const LinearGradient( - colors: [Color(0xFFEFF6FF), Color(0xFFEFF6FF)], // blue-50 to blue-50 - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: const Color(0xFFE8F0FF), - borderRadius: BorderRadius.circular(8), - ), - child: const Icon( - LucideIcons.dollarSign, - color: Color(0xFF0047FF), - size: 20, - ), - ), - const SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Pending", - style: TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), // slate-900 - fontSize: 14, - ), - ), - Text( - "\$${amount.toStringAsFixed(0)} available", - style: const TextStyle( - fontSize: 12, - color: Color(0xFF475569), // slate-600 - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ], - ), - ElevatedButton.icon( - onPressed: onCashOut, - icon: const Icon(LucideIcons.zap, size: 14), - label: const Text("Early Pay"), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0047FF), - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), - elevation: 4, - shadowColor: Colors.black.withOpacity(0.2), - textStyle: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/scaffold_with_nav_bar.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/scaffold_with_nav_bar.dart deleted file mode 100644 index 041232ae..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/scaffold_with_nav_bar.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'dart:ui'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../theme.dart'; - -class ScaffoldWithNavBar extends StatelessWidget { - const ScaffoldWithNavBar({required this.navigationShell, super.key}); - - final StatefulNavigationShell navigationShell; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: navigationShell, - extendBody: true, - bottomNavigationBar: _buildBottomBar(context), - ); - } - - Widget _buildBottomBar(BuildContext context) { - // TODO: Get from provider - bool isWorker = true; - final activeColor = isWorker ? AppColors.krowBlue : AppColors.krowCharcoal; - final inactiveColor = const Color(0xFF8E8E93); - - return Stack( - clipBehavior: Clip.none, - children: [ - Positioned.fill( - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.85), - border: const Border( - top: BorderSide(color: Color.fromRGBO(0, 0, 0, 0.1)), - ), - ), - ), - ), - ), - ), - Container( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 8, - top: 16, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - _buildNavItem( - 0, - LucideIcons.briefcase, - 'Shifts', - activeColor, - inactiveColor, - ), - _buildNavItem( - 1, - LucideIcons.dollarSign, - 'Payments', - activeColor, - inactiveColor, - ), - _buildNavItem( - 2, - LucideIcons.home, - 'Home', - activeColor, - inactiveColor, - ), - _buildNavItem( - 3, - LucideIcons.clock, - 'Clock In', - activeColor, - inactiveColor, - ), - _buildNavItem( - 4, - LucideIcons.users, - 'Profile', - activeColor, - inactiveColor, - ), - ], - ), - ), - ], - ); - } - - Widget _buildNavItem( - int index, - IconData icon, - String label, - Color activeColor, - Color inactiveColor, - ) { - final isSelected = navigationShell.currentIndex == index; - return Expanded( - child: GestureDetector( - onTap: () => _onTap(index), - behavior: HitTestBehavior.opaque, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Icon( - icon, - color: isSelected ? activeColor : inactiveColor, - size: 24, - ), - const SizedBox(height: 2), - Text( - label, - style: TextStyle( - color: isSelected ? activeColor : inactiveColor, - fontSize: 10, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ); - } - - void _onTap(int index) { - navigationShell.goBranch( - index, - initialLocation: index == navigationShell.currentIndex, - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shift_card.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shift_card.dart deleted file mode 100644 index d3817305..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shift_card.dart +++ /dev/null @@ -1,495 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../models/shift.dart'; -import '../theme.dart'; - -class ShiftCard extends StatefulWidget { - final Shift shift; - final VoidCallback? onApply; - final VoidCallback? onDecline; - final bool compact; - final bool disableTapNavigation; // Added property - - const ShiftCard({ - super.key, - required this.shift, - this.onApply, - this.onDecline, - this.compact = false, - this.disableTapNavigation = false, // Default to false - }); - - @override - State createState() => _ShiftCardState(); -} - -class _ShiftCardState extends State { - bool isExpanded = false; - - String _formatTime(String time) { - if (time.isEmpty) return ''; - try { - final parts = time.split(':'); - final hour = int.parse(parts[0]); - final minute = int.parse(parts[1]); - final dt = DateTime(2022, 1, 1, hour, minute); - return DateFormat('h:mma').format(dt).toLowerCase(); - } catch (e) { - return time; - } - } - - String _formatDate(String dateStr) { - if (dateStr.isEmpty) return ''; - try { - final date = DateTime.parse(dateStr); - return DateFormat('MMMM d').format(date); - } catch (e) { - return dateStr; - } - } - - String _getTimeAgo(String dateStr) { - if (dateStr.isEmpty) return ''; - try { - final date = DateTime.parse(dateStr); - final diff = DateTime.now().difference(date); - if (diff.inHours < 1) return 'Just now'; - if (diff.inHours < 24) return 'Pending ${diff.inHours}h ago'; - return 'Pending ${diff.inDays}d ago'; - } catch (e) { - return ''; - } - } - - Map _calculateDuration() { - if (widget.shift.startTime.isEmpty || widget.shift.endTime.isEmpty) { - return {'hours': 0, 'breakTime': '1 hour'}; - } - try { - final startParts = widget.shift.startTime - .split(':') - .map(int.parse) - .toList(); - final endParts = widget.shift.endTime.split(':').map(int.parse).toList(); - double hours = - (endParts[0] - startParts[0]) + (endParts[1] - startParts[1]) / 60; - if (hours < 0) hours += 24; - return {'hours': hours.round(), 'breakTime': '1 hour'}; - } catch (e) { - return {'hours': 0, 'breakTime': '1 hour'}; - } - } - - @override - Widget build(BuildContext context) { - if (widget.compact) { - return GestureDetector( - onTap: widget.disableTapNavigation - ? null - : () { - setState(() => isExpanded = !isExpanded); - GoRouter.of( - context, - ).push('/shift-details/${widget.shift.id}', extra: widget.shift); - }, - child: Container( - margin: const EdgeInsets.only(bottom: 12), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: widget.shift.logoUrl != null - ? ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Image.network( - widget.shift.logoUrl!, - fit: BoxFit.contain, - ), - ) - : const Icon( - LucideIcons.building2, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text( - widget.shift.title, - style: const TextStyle( - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - overflow: TextOverflow.ellipsis, - ), - ), - Text.rich( - TextSpan( - text: '\$${widget.shift.hourlyRate}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - color: AppColors.krowCharcoal, - ), - children: const [ - TextSpan( - text: '/h', - style: TextStyle( - fontWeight: FontWeight.normal, - fontSize: 12, - ), - ), - ], - ), - ), - ], - ), - Text( - widget.shift.clientName, - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 13, - ), - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - Text( - '${_formatTime(widget.shift.startTime)} • ${widget.shift.location}', - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 12, - ), - ), - ], - ), - ), - ], - ), - ), - ); - } - - return Container( - margin: const EdgeInsets.only(bottom: 16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.05), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - // Header - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - width: 56, - height: 56, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: AppColors.krowBorder), - ), - child: widget.shift.logoUrl != null - ? ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Image.network( - widget.shift.logoUrl!, - fit: BoxFit.contain, - ), - ) - : const Icon( - LucideIcons.building2, - size: 28, - color: AppColors.krowBlue, - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 6, - ), - decoration: BoxDecoration( - color: AppColors.krowBlue, - borderRadius: BorderRadius.circular(20), - ), - child: Text( - 'Assigned ${_getTimeAgo(widget.shift.createdDate).replaceAll('Pending ', '')}', - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - ], - ), - const SizedBox(height: 16), - - // Title and Rate - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.shift.title, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - widget.shift.clientName, - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - ], - ), - ), - Text.rich( - TextSpan( - text: '\$${widget.shift.hourlyRate}', - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 20, - color: AppColors.krowCharcoal, - ), - children: const [ - TextSpan( - text: '/h', - style: TextStyle( - fontWeight: FontWeight.normal, - fontSize: 16, - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 16), - - // Location and Date - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 16, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Expanded( - child: Text( - widget.shift.location, - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - overflow: TextOverflow.ellipsis, - ), - ), - const SizedBox(width: 16), - const Icon( - LucideIcons.calendar, - size: 16, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Text( - '${_formatDate(widget.shift.date)}, ${_formatTime(widget.shift.startTime)}', - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - ], - ), - const SizedBox(height: 16), - - // Tags - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - _buildTag( - LucideIcons.zap, - 'Immediate start', - AppColors.krowYellow.withValues(alpha: 0.3), - AppColors.krowCharcoal, - ), - _buildTag( - LucideIcons.timer, - 'No experience', - const Color(0xFFFEE2E2), - const Color(0xFFDC2626), - ), - ], - ), - - const SizedBox(height: 16), - ], - ), - ), - - // Actions - if (!widget.compact) - Padding( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 0), - child: Column( - children: [ - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: widget.onApply, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowCharcoal, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - 'Accept shift', - style: TextStyle(fontWeight: FontWeight.w600), - ), - ), - ), - const SizedBox(height: 8), - SizedBox( - width: double.infinity, - height: 48, - child: OutlinedButton( - onPressed: widget.onDecline, - style: OutlinedButton.styleFrom( - foregroundColor: const Color(0xFFEF4444), - side: const BorderSide(color: Color(0xFFFCA5A5)), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - 'Decline shift', - style: TextStyle(fontWeight: FontWeight.w600), - ), - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildTag(IconData icon, String label, Color bg, Color text) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: bg, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(icon, size: 14, color: text), - const SizedBox(width: 4), - Flexible( - child: Text( - label, - style: TextStyle( - color: text, - fontSize: 12, - fontWeight: FontWeight.w600, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ); - } - - Widget _buildDetailRow(IconData icon, String label, bool? value) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 12), - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: AppColors.krowBorder)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Icon(icon, size: 16, color: AppColors.krowMuted), - const SizedBox(width: 8), - Text( - label, - style: const TextStyle( - color: AppColors.krowMuted, - fontSize: 14, - ), - ), - ], - ), - Text( - value == true ? 'Yes' : 'No', - style: TextStyle( - color: value == true - ? const Color(0xFF10B981) - : AppColors.krowMuted, - fontWeight: FontWeight.w600, - fontSize: 14, - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shifts/my_shift_card.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shifts/my_shift_card.dart deleted file mode 100644 index 7044a92b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shifts/my_shift_card.dart +++ /dev/null @@ -1,775 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../theme.dart'; -import '../../models/shift.dart'; - -class MyShiftCard extends StatefulWidget { - final Shift shift; - final bool historyMode; - final VoidCallback? onAccept; - final VoidCallback? onDecline; - final VoidCallback? onRequestSwap; - final int index; - - const MyShiftCard({ - super.key, - required this.shift, - this.historyMode = false, - this.onAccept, - this.onDecline, - this.onRequestSwap, - this.index = 0, - }); - - @override - State createState() => _MyShiftCardState(); -} - -class _MyShiftCardState extends State { - bool _isExpanded = false; - - String _formatTime(String time) { - if (time.isEmpty) return ''; - try { - final parts = time.split(':'); - final hour = int.parse(parts[0]); - final minute = int.parse(parts[1]); - final dt = DateTime(2022, 1, 1, hour, minute); - return DateFormat('h:mm a').format(dt); - } catch (e) { - return time; - } - } - - String _formatDate(String dateStr) { - if (dateStr.isEmpty) return ''; - try { - final date = DateTime.parse(dateStr); - final now = DateTime.now(); - final today = DateTime(now.year, now.month, now.day); - final tomorrow = today.add(const Duration(days: 1)); - final d = DateTime(date.year, date.month, date.day); - - if (d == today) return 'Today'; - if (d == tomorrow) return 'Tomorrow'; - return DateFormat('EEE, MMM d').format(date); - } catch (e) { - return dateStr; - } - } - - double _calculateDuration() { - if (widget.shift.startTime.isEmpty || widget.shift.endTime.isEmpty) - return 0; - try { - final s = widget.shift.startTime.split(':').map(int.parse).toList(); - final e = widget.shift.endTime.split(':').map(int.parse).toList(); - double hours = ((e[0] * 60 + e[1]) - (s[0] * 60 + s[1])) / 60; - if (hours < 0) hours += 24; - return hours.roundToDouble(); - } catch (_) { - return 0; - } - } - - String _getShiftType() { - // Check title for type indicators (for mock data) - if (widget.shift.title.contains('Long Term')) return 'Long Term'; - if (widget.shift.title.contains('Multi-Day')) return 'Multi-Day'; - return 'One Day'; - } - - @override - Widget build(BuildContext context) { - final duration = _calculateDuration(); - final estimatedTotal = (widget.shift.hourlyRate) * duration; - - // Status Logic - String? status = widget.shift.status; - Color statusColor = AppColors.krowBlue; - Color statusBg = AppColors.krowBlue; - String statusText = ''; - IconData? statusIcon; - - if (status == 'confirmed') { - statusText = 'CONFIRMED'; - statusColor = AppColors.krowBlue; - statusBg = AppColors.krowBlue; - } else if (status == 'pending' || status == 'open') { - statusText = 'ACT NOW'; - statusColor = const Color(0xFFDC2626); - statusBg = const Color(0xFFEF4444); - } else if (status == 'swap') { - statusText = 'SWAP REQUESTED'; - statusColor = const Color(0xFFF59E0B); - statusBg = const Color(0xFFF59E0B); - statusIcon = LucideIcons.arrowLeftRight; - } else if (status == 'completed') { - statusText = 'COMPLETED'; - statusColor = const Color(0xFF10B981); - statusBg = const Color(0xFF10B981); - } else if (status == 'no_show') { - statusText = 'NO SHOW'; - statusColor = const Color(0xFFEF4444); - statusBg = const Color(0xFFEF4444); - } - - return GestureDetector( - onTap: () => setState(() => _isExpanded = !_isExpanded), - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - // Collapsed Content - Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Status Badge - if (statusText.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - children: [ - if (statusIcon != null) - Padding( - padding: const EdgeInsets.only(right: 6), - child: Icon( - statusIcon, - size: 12, - color: statusColor, - ), - ) - else - Container( - width: 6, - height: 6, - margin: const EdgeInsets.only(right: 6), - decoration: BoxDecoration( - color: statusBg, - shape: BoxShape.circle, - ), - ), - Text( - statusText, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.w600, - color: statusColor, - letterSpacing: 0.5, - ), - ), - // Shift Type Badge for available/pending shifts - if (status == 'open' || status == 'pending') ...[ - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), - decoration: BoxDecoration( - color: AppColors.krowBlue.withOpacity(0.1), - borderRadius: BorderRadius.circular(4), - ), - child: Text( - _getShiftType(), - style: TextStyle( - fontSize: 8, - fontWeight: FontWeight.w500, - color: AppColors.krowBlue, - ), - ), - ), - ], - ], - ), - ), - - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Logo - Container( - width: 44, - height: 44, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - AppColors.krowBlue.withOpacity(0.09), - AppColors.krowBlue.withOpacity(0.03), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: AppColors.krowBlue.withOpacity(0.09), - ), - ), - child: widget.shift.logoUrl != null - ? ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Image.network( - widget.shift.logoUrl!, - fit: BoxFit.contain, - ), - ) - : const Center( - child: Icon( - LucideIcons.briefcase, - color: AppColors.krowBlue, - size: 20, - ), - ), - ), - const SizedBox(width: 12), - - // Details - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - widget.shift.title, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - overflow: TextOverflow.ellipsis, - ), - Text( - widget.shift.clientName, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - const SizedBox(width: 8), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - "\$${estimatedTotal.toStringAsFixed(0)}", - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - "\$${widget.shift.hourlyRate}/hr · ${duration}h", - style: const TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - const SizedBox(height: 8), - - // Date & Time - Multi-Day or Single Day - if (_getShiftType() == 'Multi-Day' && - widget.shift.durationDays != null) ...[ - // Multi-Day Schedule Display - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.clock, - size: 12, - color: AppColors.krowBlue, - ), - const SizedBox(width: 4), - Text( - '${widget.shift.durationDays} schedules', - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: AppColors.krowBlue, - ), - ), - ], - ), - const SizedBox(height: 4), - ...List.generate(widget.shift.durationDays!, ( - index, - ) { - final shiftDate = DateTime.parse( - widget.shift.date, - ); - final scheduleDate = shiftDate.add( - Duration(days: index), - ); - final dayName = DateFormat( - 'E', - ).format(scheduleDate); - final dateStr = DateFormat( - 'MMM d', - ).format(scheduleDate); - - return Padding( - padding: const EdgeInsets.only(bottom: 2), - child: Text( - '$dayName, $dateStr ${_formatTime(widget.shift.startTime)} – ${_formatTime(widget.shift.endTime)}', - style: const TextStyle( - fontSize: 10, - color: AppColors.krowBlue, - ), - ), - ); - }), - ], - ), - ] else ...[ - // Single Day Display - Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - _formatDate(widget.shift.date), - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 12), - const Icon( - LucideIcons.clock, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Text( - "${_formatTime(widget.shift.startTime)} - ${_formatTime(widget.shift.endTime)}", - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - const SizedBox(height: 4), - - // Location - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 12, - color: AppColors.krowMuted, - ), - const SizedBox(width: 4), - Expanded( - child: Text( - widget.shift.locationAddress.isNotEmpty - ? widget.shift.locationAddress - : widget.shift.location, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ], - ), - ), - ], - ), - ], - ), - ), - - // Expanded Content - AnimatedSize( - duration: const Duration(milliseconds: 300), - child: _isExpanded - ? Column( - children: [ - const Divider(height: 1, color: AppColors.krowBorder), - Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - // Stats Row - Row( - children: [ - Expanded( - child: _buildStatCard( - LucideIcons.dollarSign, - "\$${estimatedTotal.toStringAsFixed(0)}", - "Total", - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildStatCard( - LucideIcons.dollarSign, - "\$${widget.shift.hourlyRate}", - "Hourly Rate", - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildStatCard( - LucideIcons.timer, - "${duration}", - "Hours", - ), - ), - ], - ), - const SizedBox(height: 24), - - // In/Out Time - Row( - children: [ - Expanded( - child: _buildTimeBox( - "CLOCK IN TIME", - widget.shift.startTime, - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildTimeBox( - "CLOCK OUT TIME", - widget.shift.endTime, - ), - ), - ], - ), - const SizedBox(height: 24), - - // Location - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "LOCATION", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - letterSpacing: 0.5, - ), - ), - const SizedBox(height: 8), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.shift.location.isEmpty - ? "TBD" - : widget.shift.location, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - OutlinedButton.icon( - onPressed: () { - // Show snackbar with the address - ScaffoldMessenger.of( - context, - ).showSnackBar( - SnackBar( - content: Text( - widget.shift.locationAddress ?? - widget.shift.location, - ), - duration: const Duration( - seconds: 3, - ), - ), - ); - }, - icon: const Icon( - LucideIcons.navigation, - size: 14, - ), - label: const Text( - "Get direction", - style: TextStyle(fontSize: 12), - ), - style: OutlinedButton.styleFrom( - foregroundColor: - AppColors.krowCharcoal, - side: const BorderSide( - color: AppColors.krowBorder, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - 20, - ), - ), - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 0, - ), - minimumSize: const Size(0, 32), - ), - ), - ], - ), - const SizedBox(height: 12), - Container( - height: 128, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(12), - ), - // Placeholder for Map - ), - ], - ), - const SizedBox(height: 24), - - // Additional Info - if (widget.shift.description != null) ...[ - SizedBox( - width: double.infinity, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - const Text( - "ADDITIONAL INFO", - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - letterSpacing: 0.5, - ), - ), - const SizedBox(height: 8), - Text( - widget.shift.description!.split('.')[0], - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - Text( - widget.shift.description!, - style: const TextStyle( - fontSize: 14, - color: AppColors.krowMuted, - ), - ), - ], - ), - ), - const SizedBox(height: 24), - ], - - // Actions - if (!widget.historyMode) - if (status == 'confirmed') - SizedBox( - width: double.infinity, - height: 48, - child: OutlinedButton.icon( - onPressed: widget.onRequestSwap, - icon: const Icon( - LucideIcons.arrowLeftRight, - size: 16, - ), - label: const Text("Request Swap"), - style: OutlinedButton.styleFrom( - foregroundColor: AppColors.krowBlue, - side: const BorderSide( - color: AppColors.krowBlue, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - 12, - ), - ), - ), - ), - ) - else if (status == 'swap') - Container( - width: double.infinity, - height: 48, - decoration: BoxDecoration( - color: const Color( - 0xFFFFFBEB, - ), // amber-50 - border: Border.all( - color: const Color(0xFFFDE68A), - ), // amber-200 - borderRadius: BorderRadius.circular(12), - ), - child: const Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Icon( - LucideIcons.arrowLeftRight, - size: 16, - color: Color(0xFFB45309), - ), // amber-700 - SizedBox(width: 8), - Text( - "Swap Pending", - style: TextStyle( - fontWeight: FontWeight.w600, - color: Color(0xFFB45309), - ), - ), - ], - ), - ) - else - Column( - children: [ - SizedBox( - width: double.infinity, - height: 48, - child: ElevatedButton( - onPressed: widget.onAccept, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12), - ), - ), - child: const Text( - "Book Shift", - style: TextStyle( - fontWeight: FontWeight.w600, - ), - ), - ), - ), - ], - ), - ], - ), - ), - ], - ) - : const SizedBox.shrink(), - ), - ], - ), - ), - ); - } - - Widget _buildStatCard(IconData icon, String value, String label) { - return Container( - padding: const EdgeInsets.symmetric(vertical: 16), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.krowBorder), - ), - child: Column( - children: [ - Container( - width: 40, - height: 40, - decoration: const BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: Icon(icon, size: 20, color: AppColors.krowMuted), - ), - const SizedBox(height: 8), - Text( - value, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - label, - style: const TextStyle(fontSize: 10, color: AppColors.krowMuted), - ), - ], - ), - ); - } - - Widget _buildTimeBox(String label, String time) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: const Color(0xFFF8FAFC), - borderRadius: BorderRadius.circular(16), - ), - child: Column( - children: [ - Text( - label, - style: const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: AppColors.krowMuted, - letterSpacing: 0.5, - ), - ), - const SizedBox(height: 4), - Text( - _formatTime(time), - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shifts/shift_assignment_card.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shifts/shift_assignment_card.dart deleted file mode 100644 index 2b7413de..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/shifts/shift_assignment_card.dart +++ /dev/null @@ -1,282 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:intl/intl.dart'; -import '../../theme.dart'; -import '../../models/shift.dart'; - -class ShiftAssignmentCard extends StatelessWidget { - final Shift shift; - final VoidCallback onConfirm; - final VoidCallback onDecline; - final bool isConfirming; - - const ShiftAssignmentCard({ - super.key, - required this.shift, - required this.onConfirm, - required this.onDecline, - this.isConfirming = false, - }); - - String _formatTime(String time) { - if (time.isEmpty) return ''; - try { - final parts = time.split(':'); - final hour = int.parse(parts[0]); - final minute = int.parse(parts[1]); - final dt = DateTime(2022, 1, 1, hour, minute); - return DateFormat('h:mm a').format(dt); - } catch (e) { - return time; - } - } - - String _formatDate(String dateStr) { - if (dateStr.isEmpty) return ''; - try { - final date = DateTime.parse(dateStr); - final now = DateTime.now(); - final today = DateTime(now.year, now.month, now.day); - final tomorrow = today.add(const Duration(days: 1)); - final d = DateTime(date.year, date.month, date.day); - - if (d == today) return 'Today'; - if (d == tomorrow) return 'Tomorrow'; - return DateFormat('EEE, MMM d').format(date); - } catch (e) { - return dateStr; - } - } - - double _calculateHours(String start, String end) { - if (start.isEmpty || end.isEmpty) return 0; - try { - final s = start.split(':').map(int.parse).toList(); - final e = end.split(':').map(int.parse).toList(); - return ((e[0] * 60 + e[1]) - (s[0] * 60 + s[1])) / 60; - } catch (_) { - return 0; - } - } - - @override - Widget build(BuildContext context) { - final hours = _calculateHours(shift.startTime, shift.endTime); - final totalPay = shift.hourlyRate * hours; - - return Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.grey.shade200), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - // Header - Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - width: 36, - height: 36, - decoration: BoxDecoration( - color: Colors.grey.shade100, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Text( - shift.clientName.isNotEmpty - ? shift.clientName[0] - : 'K', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Colors.grey.shade600, - ), - ), - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - shift.title, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: AppColors.krowCharcoal, - ), - ), - Text( - shift.clientName, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - "\$${totalPay.toStringAsFixed(0)}", - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: AppColors.krowCharcoal, - ), - ), - Text( - "\$${shift.hourlyRate}/hr · ${hours}h", - style: const TextStyle( - fontSize: 10, - color: AppColors.krowMuted, - ), - ), - ], - ), - ], - ), - ), - - // Details - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Icon( - LucideIcons.calendar, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Text( - _formatDate(shift.date), - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - const SizedBox(width: 16), - const Icon( - LucideIcons.clock, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Text( - "${_formatTime(shift.startTime)} - ${_formatTime(shift.endTime)}", - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - const Icon( - LucideIcons.mapPin, - size: 14, - color: AppColors.krowMuted, - ), - const SizedBox(width: 6), - Expanded( - child: Text( - shift.locationAddress.isNotEmpty - ? shift.locationAddress - : shift.location, - style: const TextStyle( - fontSize: 12, - color: AppColors.krowMuted, - ), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - // Skills would go here if they were in the Shift model - ], - ), - ), - - // Actions - Padding( - padding: const EdgeInsets.fromLTRB(16, 4, 16, 16), - child: Row( - children: [ - Expanded( - child: SizedBox( - height: 36, - child: OutlinedButton( - onPressed: onDecline, - style: OutlinedButton.styleFrom( - foregroundColor: AppColors.krowMuted, - side: BorderSide(color: Colors.grey.shade200), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: EdgeInsets.zero, - ), - child: const Text( - "Decline", - style: TextStyle(fontSize: 12), - ), - ), - ), - ), - const SizedBox(width: 8), - Expanded( - child: SizedBox( - height: 36, - child: ElevatedButton( - onPressed: isConfirming ? null : onConfirm, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.krowBlue, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: EdgeInsets.zero, - disabledBackgroundColor: AppColors.krowBlue.withOpacity( - 0.6, - ), - ), - child: Text( - isConfirming ? "Confirming..." : "Confirm", - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - ), - ), - ), - ), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/web_mobile_frame.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/web_mobile_frame.dart deleted file mode 100644 index 8b515056..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/web_mobile_frame.dart +++ /dev/null @@ -1,271 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:google_fonts/google_fonts.dart'; - -/// A wrapper widget that renders the application inside an iPhone 14 Pro Max-like frame -/// specifically for Flutter Web. On other platforms, it simply returns the child. -class WebMobileFrame extends StatelessWidget { - final Widget child; - - const WebMobileFrame({super.key, required this.child}); - - @override - Widget build(BuildContext context) { - if (!kIsWeb) return child; - - return MaterialApp( - debugShowCheckedModeBanner: false, - theme: ThemeData.dark(), - home: _WebFrameContent(child: child), - ); - } -} - -class _WebFrameContent extends StatefulWidget { - final Widget child; - const _WebFrameContent({required this.child}); - - @override - State<_WebFrameContent> createState() => _WebFrameContentState(); -} - -class _WebFrameContentState extends State<_WebFrameContent> { - Offset _cursorPosition = Offset.zero; - bool _isHovering = false; - - @override - Widget build(BuildContext context) { - // iPhone 14 Pro Max-ish dimensions (scaled for frame look) - const double frameWidth = 390 * 1.2; - const double frameHeight = 844 * 1.3; - const double borderRadius = 54.0; - const double borderThickness = 12.0; - - return Scaffold( - backgroundColor: const Color(0xFF121212), - body: MouseRegion( - cursor: SystemMouseCursors.none, - onHover: (event) { - setState(() { - _cursorPosition = event.position; - _isHovering = true; - }); - }, - onExit: (_) => setState(() => _isHovering = false), - child: Stack( - children: [ - // Logo and Title on the left (Web only) - Positioned( - left: 60, - top: 0, - bottom: 0, - child: Center( - child: Opacity( - opacity: 0.5, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.asset('assets/logo.png', width: 140), - const SizedBox(height: 12), - Text( - 'KROW Staff \nApplication', - textAlign: TextAlign.left, - style: GoogleFonts.instrumentSans( - color: Colors.white, - fontSize: 28, - fontWeight: FontWeight.bold, - letterSpacing: -0.5, - ), - ), - const SizedBox(height: 4), - Container( - height: 2, - width: 40, - color: Colors.white.withOpacity(0.3), - ), - ], - ), - ), - ), - ), - - // Frame and Content - Center( - child: LayoutBuilder( - builder: (context, constraints) { - // Scale down if screen is too small - double scaleX = constraints.maxWidth / (frameWidth + 80); - double scaleY = constraints.maxHeight / (frameHeight + 80); - double scale = (scaleX < 1 || scaleY < 1) - ? (scaleX < scaleY ? scaleX : scaleY) - : 1.0; - - return Transform.scale( - scale: scale, - child: Container( - width: frameWidth, - height: frameHeight, - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(borderRadius), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.6), - blurRadius: 40, - spreadRadius: 10, - ), - ], - border: Border.all( - color: const Color(0xFF2C2C2C), - width: borderThickness, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular( - borderRadius - borderThickness, - ), - child: Stack( - children: [ - // The actual app + status bar - Column( - children: [ - // Mock iOS Status Bar - Container( - height: 48, - padding: const EdgeInsets.symmetric( - horizontal: 24, - ), - decoration: const BoxDecoration( - color: Color(0xFFF9F6EE), - border: Border( - bottom: BorderSide( - color: Color(0xFFEEEEEE), - width: 0.5, - ), - ), - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - // Time side - const SizedBox( - width: 80, - child: Text( - '3:12 PM', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.black54, - fontWeight: FontWeight.w700, - fontSize: 14, - letterSpacing: -0.2, - ), - ), - ), - // Status Icons side - const SizedBox( - width: 80, - child: Row( - mainAxisAlignment: - MainAxisAlignment.end, - spacing: 12, - children: [ - Icon( - FontAwesomeIcons.signal, - size: 12, - color: Colors.black54, - ), - Icon( - FontAwesomeIcons.wifi, - size: 12, - color: Colors.black54, - ), - Icon( - FontAwesomeIcons.batteryFull, - size: 12, - color: Colors.black54, - ), - ], - ), - ), - ], - ), - ), - // The main app content content - Expanded(child: widget.child), - ], - ), - - // Notch / Dynamic Island - Align( - alignment: Alignment.topCenter, - child: Padding( - padding: const EdgeInsets.only(top: 8), - child: Container( - width: 125, - height: 35, - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Container( - width: 8, - height: 8, - margin: const EdgeInsets.only( - right: 20, - ), - decoration: const BoxDecoration( - color: Color(0xFF0F0F0F), - shape: BoxShape.circle, - ), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ), - ); - }, - ), - ), - - // Custom Circle Cursor - if (_isHovering) - Positioned( - left: _cursorPosition.dx - 20, - top: _cursorPosition.dy - 20, - child: IgnorePointer( - child: ClipRRect( - borderRadius: BorderRadius.circular(25), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 2.5, sigmaY: 2.5), - child: Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.grey.withAlpha(50), - shape: BoxShape.circle, - border: Border.all(color: Colors.white, width: 1.5), - ), - ), - ), - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/auto_match_toggle.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/auto_match_toggle.dart deleted file mode 100644 index a0d0de1e..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/auto_match_toggle.dart +++ /dev/null @@ -1,166 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import '../../theme.dart'; - -class AutoMatchToggle extends StatefulWidget { - final bool enabled; - final ValueChanged onToggle; - - const AutoMatchToggle({ - super.key, - required this.enabled, - required this.onToggle, - }); - - @override - State createState() => _AutoMatchToggleState(); -} - -class _AutoMatchToggleState extends State - with SingleTickerProviderStateMixin { - @override - Widget build(BuildContext context) { - return AnimatedContainer( - duration: const Duration(milliseconds: 300), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - gradient: widget.enabled - ? const LinearGradient( - colors: [Color(0xFF0032A0), Color(0xFF0047CC)], - begin: Alignment.centerLeft, - end: Alignment.centerRight, - ) - : null, - color: widget.enabled ? null : Colors.white, - border: widget.enabled ? null : Border.all(color: Colors.grey.shade200), - boxShadow: widget.enabled - ? [ - BoxShadow( - color: const Color(0xFF0032A0).withOpacity(0.3), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ] - : null, - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: widget.enabled - ? Colors.white.withOpacity(0.2) - : const Color(0xFF0032A0).withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Icon( - LucideIcons.zap, - color: widget.enabled - ? Colors.white - : const Color(0xFF0032A0), - size: 20, - ), - ), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Auto-Match", - style: TextStyle( - fontWeight: FontWeight.bold, - color: widget.enabled - ? Colors.white - : const Color(0xFF0F172A), // slate-900 - ), - ), - Text( - widget.enabled - ? "Finding shifts for you" - : "Get matched automatically", - style: TextStyle( - fontSize: 12, - color: widget.enabled - ? const Color(0xFFF8E08E) - : Colors.grey.shade500, - ), - ), - ], - ), - ], - ), - Switch( - value: widget.enabled, - onChanged: widget.onToggle, - activeColor: Colors.white, - activeTrackColor: Colors.white.withOpacity(0.3), - inactiveThumbColor: Colors.white, - inactiveTrackColor: Colors.grey.shade300, - ), - ], - ), - AnimatedSize( - duration: const Duration(milliseconds: 300), - child: widget.enabled - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 16), - Container( - height: 1, - color: Colors.white.withOpacity(0.2), - ), - const SizedBox(height: 16), - const Text( - "Matching based on:", - style: TextStyle( - color: Color(0xFFF8E08E), - fontSize: 12, - ), - ), - const SizedBox(height: 12), - Wrap( - spacing: 8, - children: [ - _buildChip(LucideIcons.mapPin, "Location"), - _buildChip(LucideIcons.clock, "Availability"), - _buildChip(LucideIcons.briefcase, "Skills"), - ], - ), - ], - ) - : const SizedBox.shrink(), - ), - ], - ), - ); - } - - Widget _buildChip(IconData icon, String label) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.2), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(icon, size: 12, color: Colors.white), - const SizedBox(width: 4), - Text( - label, - style: const TextStyle(color: Colors.white, fontSize: 12), - ), - ], - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/benefits_widget.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/benefits_widget.dart deleted file mode 100644 index 2f5c7d09..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/benefits_widget.dart +++ /dev/null @@ -1,199 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lucide_icons/lucide_icons.dart'; -import 'package:go_router/go_router.dart'; -import 'dart:math' as math; -import '../../theme.dart'; - -class BenefitsWidget extends StatelessWidget { - const BenefitsWidget({super.key}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - "Your Benefits", - style: TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xFF0F172A), - ), // slate-900 - ), - GestureDetector( - onTap: () => context.push('/benefits'), - child: const Row( - children: [ - Text( - "View all", - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Color(0xFF0032A0), - ), - ), - Icon( - LucideIcons.chevronRight, - size: 16, - color: Color(0xFF0032A0), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 16), - const Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - _BenefitItem( - label: "Sick Days", - current: 10, - total: 40, - color: Color(0xFF0A39DF), - ), - _BenefitItem( - label: "Vacation", - current: 40, - total: 40, - color: Color(0xFF0A39DF), - ), - _BenefitItem( - label: "Holidays", - current: 24, - total: 24, - color: Color(0xFF0A39DF), - ), - ], - ), - ], - ), - ); - } -} - -class _BenefitItem extends StatelessWidget { - final String label; - final double current; - final double total; - final Color color; - - const _BenefitItem({ - required this.label, - required this.current, - required this.total, - required this.color, - }); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - SizedBox( - width: 56, - height: 56, - child: CustomPaint( - painter: _CircularProgressPainter( - progress: current / total, - color: color, - backgroundColor: const Color(0xFFE5E7EB), // slate-200 - strokeWidth: 4, - ), - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "${current.toInt()}/${total.toInt()}", - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Color(0xFF1E293B), // slate-800 - ), - ), - const Text( - "hours", - style: TextStyle( - fontSize: 8, - color: Color(0xFF94A3B8), // slate-400 - ), - ), - ], - ), - ), - ), - ), - const SizedBox(height: 8), - Text( - label, - style: const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Color(0xFF475569), // slate-600 - ), - ), - ], - ); - } -} - -class _CircularProgressPainter extends CustomPainter { - final double progress; - final Color color; - final Color backgroundColor; - final double strokeWidth; - - _CircularProgressPainter({ - required this.progress, - required this.color, - required this.backgroundColor, - required this.strokeWidth, - }); - - @override - void paint(Canvas canvas, Size size) { - final center = Offset(size.width / 2, size.height / 2); - final radius = (size.width - strokeWidth) / 2; - - final backgroundPaint = Paint() - ..color = backgroundColor - ..style = PaintingStyle.stroke - ..strokeWidth = strokeWidth; - - canvas.drawCircle(center, radius, backgroundPaint); - - final progressPaint = Paint() - ..color = color - ..style = PaintingStyle.stroke - ..strokeWidth = strokeWidth - ..strokeCap = StrokeCap.round; - - final sweepAngle = 2 * math.pi * progress; - // Start from top (-pi/2) - canvas.drawArc( - Rect.fromCircle(center: center, radius: radius), - -math.pi / 2, - sweepAngle, - false, - progressPaint, - ); - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) => true; -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/improve_yourself_widget.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/improve_yourself_widget.dart deleted file mode 100644 index 4a6ab75e..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/improve_yourself_widget.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class ImproveYourselfWidget extends StatelessWidget { - const ImproveYourselfWidget({super.key}); - - final List> items = const [ - { - 'id': 'training', - 'title': 'Training Section', - 'description': 'Improve your skills and get certified.', - 'image': - 'https://images.unsplash.com/photo-1524995997946-a1c2e315a42f?w=400&h=300&fit=crop', - 'page': '/krow-university', - }, - { - 'id': 'podcast', - 'title': 'Krow Podcast', - 'description': 'Listen to tips from top workers.', - 'image': - 'https://images.unsplash.com/photo-1478737270239-2f02b77fc618?w=400&h=300&fit=crop', - 'page': '/krow-university', - }, - ]; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "Improve Yourself", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 12), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - clipBehavior: Clip.none, - child: Row( - children: items.map((item) => _buildCard(context, item)).toList(), - ), - ), - ], - ); - } - - Widget _buildCard(BuildContext context, Map item) { - return GestureDetector( - onTap: () => context.push(item['page']!), - child: Container( - width: 160, - margin: const EdgeInsets.only(right: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - clipBehavior: Clip.antiAlias, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 96, - width: double.infinity, - child: Image.network( - item['image']!, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) => Container( - color: Colors.grey.shade200, - child: const Icon( - Icons.image_not_supported, - color: Colors.grey, - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item['title']!, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 2), - Text( - item['description']!, - style: const TextStyle( - fontSize: 12, - color: Color(0xFF64748B), // slate-500 - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/more_ways_widget.dart b/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/more_ways_widget.dart deleted file mode 100644 index 0ee2e47f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/lib/widgets/worker/more_ways_widget.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class MoreWaysToUseKrowWidget extends StatelessWidget { - const MoreWaysToUseKrowWidget({super.key}); - - final List> items = const [ - { - 'id': 'benefits', - 'title': 'Krow Benefits', - 'image': - 'https://images.unsplash.com/photo-1481627834876-b7833e8f5570?w=400&h=300&fit=crop', - 'page': '/benefits', - }, - { - 'id': 'refer', - 'title': 'Refer a Friend', - 'image': - 'https://images.unsplash.com/photo-1529156069898-49953e39b3ac?w=400&h=300&fit=crop', - 'page': '/worker-profile', - }, - ]; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - "More Ways To Use Krow", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - const SizedBox(height: 12), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - clipBehavior: Clip.none, - child: Row( - children: items.map((item) => _buildCard(context, item)).toList(), - ), - ), - ], - ); - } - - Widget _buildCard(BuildContext context, Map item) { - return GestureDetector( - onTap: () => context.push(item['page']!), - child: Container( - width: 160, - margin: const EdgeInsets.only(right: 12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: Colors.grey.shade100), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 2, - offset: const Offset(0, 1), - ), - ], - ), - clipBehavior: Clip.antiAlias, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 96, - width: double.infinity, - child: Image.network( - item['image']!, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) => Container( - color: Colors.grey.shade200, - child: const Icon( - Icons.image_not_supported, - color: Colors.grey, - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(12), - child: Text( - item['title']!, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF0F172A), // slate-900 - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/.gitignore b/apps/mobile/prototypes/staff_mobile_application/linux/.gitignore deleted file mode 100644 index d3896c98..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/CMakeLists.txt b/apps/mobile/prototypes/staff_mobile_application/linux/CMakeLists.txt deleted file mode 100644 index ba0b4567..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/CMakeLists.txt +++ /dev/null @@ -1,128 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "staff_app_mvp") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.staff_app_mvp") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/CMakeLists.txt b/apps/mobile/prototypes/staff_mobile_application/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd0164..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugin_registrant.cc b/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index e71a16d2..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,11 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - - -void fl_register_plugins(FlPluginRegistry* registry) { -} diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugin_registrant.h b/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugins.cmake b/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 2e1de87a..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/runner/CMakeLists.txt b/apps/mobile/prototypes/staff_mobile_application/linux/runner/CMakeLists.txt deleted file mode 100644 index e97dabc7..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/runner/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the application ID. -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/runner/main.cc b/apps/mobile/prototypes/staff_mobile_application/linux/runner/main.cc deleted file mode 100644 index e7c5c543..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/runner/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/runner/my_application.cc b/apps/mobile/prototypes/staff_mobile_application/linux/runner/my_application.cc deleted file mode 100644 index e35b1dcf..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/runner/my_application.cc +++ /dev/null @@ -1,148 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Called when first Flutter frame received. -static void first_frame_cb(MyApplication* self, FlView* view) { - gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); -} - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "staff_app_mvp"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "staff_app_mvp"); - } - - gtk_window_set_default_size(window, 1280, 720); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments( - project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - GdkRGBA background_color; - // Background defaults to black, override it here if necessary, e.g. #00000000 - // for transparent. - gdk_rgba_parse(&background_color, "#000000"); - fl_view_set_background_color(view, &background_color); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - // Show the window when Flutter renders. - // Requires the view to be realized so we can start rendering. - g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), - self); - gtk_widget_realize(GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, - gchar*** arguments, - int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GApplication::startup. -static void my_application_startup(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application startup. - - G_APPLICATION_CLASS(my_application_parent_class)->startup(application); -} - -// Implements GApplication::shutdown. -static void my_application_shutdown(GApplication* application) { - // MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application shutdown. - - G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = - my_application_local_command_line; - G_APPLICATION_CLASS(klass)->startup = my_application_startup; - G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - // Set the program name to the application ID, which helps various systems - // like GTK and desktop environments map this running application to its - // corresponding .desktop file. This ensures better integration by allowing - // the application to be recognized beyond its binary name. - g_set_prgname(APPLICATION_ID); - - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, "flags", - G_APPLICATION_NON_UNIQUE, nullptr)); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/linux/runner/my_application.h b/apps/mobile/prototypes/staff_mobile_application/linux/runner/my_application.h deleted file mode 100644 index db16367a..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/linux/runner/my_application.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, - my_application, - MY, - APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/.gitignore b/apps/mobile/prototypes/staff_mobile_application/macos/.gitignore deleted file mode 100644 index 746adbb6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/Flutter-Debug.xcconfig b/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b2..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/Flutter-Release.xcconfig b/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d15..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/GeneratedPluginRegistrant.swift b/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index f9c2b8ab..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import firebase_core -import path_provider_foundation - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) -} diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Podfile b/apps/mobile/prototypes/staff_mobile_application/macos/Podfile deleted file mode 100644 index ff5ddb3b..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Podfile +++ /dev/null @@ -1,42 +0,0 @@ -platform :osx, '10.15' - -# 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', 'ephemeral', '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 Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/project.pbxproj b/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index f0915628..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,705 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* staff_app_mvp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "staff_app_mvp.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* staff_app_mvp.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* staff_app_mvp.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/staff_app_mvp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/staff_app_mvp"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/staff_app_mvp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/staff_app_mvp"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/staff_app_mvp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/staff_app_mvp"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 8b7ea736..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcworkspace/contents.xcworkspacedata b/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/AppDelegate.swift b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c17614..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa4..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cf..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Base.lproj/MainMenu.xib b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/AppInfo.xcconfig b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 3ef081b4..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = staff_app_mvp - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.staffAppMvp - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Debug.xcconfig b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Release.xcconfig b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Warnings.xcconfig b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/DebugProfile.entitlements b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Info.plist b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/MainFlutterWindow.swift b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb2..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Release.entitlements b/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a4..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/macos/RunnerTests/RunnerTests.swift b/apps/mobile/prototypes/staff_mobile_application/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 61f3bd1f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Cocoa -import FlutterMacOS -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/apps/mobile/prototypes/staff_mobile_application/mock_staff_app_v2.md b/apps/mobile/prototypes/staff_mobile_application/mock_staff_app_v2.md deleted file mode 100644 index ce8984dd..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/mock_staff_app_v2.md +++ /dev/null @@ -1,859 +0,0 @@ -lib/services/mock_service.dart - - En este archivo, el uso de Map se encuentra como un parámetro en una función. - - 1. Parámetro de Función: Future createWorkerProfile(Map data) - - * Propósito: Esta función simula la creación de un perfil de trabajador en el backend. Acepta un Map llamado data que contiene toda la información del perfil del nuevo trabajador. - * Estructura del `Map` esperado: Aunque la función en sí misma no revela la estructura, el lugar donde se la llama (profile_setup_screen.dart) nos muestra exactamente qué datos se envían: - - 1 { - 2 'full_name': String, - 3 'bio': String, - 4 'preferred_locations': List, - 5 'max_distance_miles': double, - 6 'skills': List, - 7 'industries': List, - 8 } - - --- - - A continuación, analizaré el siguiente archivo: lib/widgets/shift_card.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/widgets/shift_card.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Continuando el análisis: - - --- - - lib/widgets/shift_card.dart - - En este widget, el uso de Map se encuentra como el tipo de retorno de una función. - - 1. Tipo de Retorno de Función: Map _calculateDuration() - - * Propósito: Esta función calcula la duración de un turno en horas y devuelve también una cadena de texto para el tiempo de descanso. - * Estructura del `Map` devuelto: - 1 { - 2 'hours': int, // La duración calculada del turno en horas. - 3 'breakTime': String, // Una cadena de texto que representa el tiempo de descanso, ej: '1 hour'. - 4 } - - --- - - Siguiente archivo: lib/screens/auth/profile_setup_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../profile_setup_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ De acuerdo, aquí está el análisis del archivo. - - --- - - lib/screens/auth/profile_setup_screen.dart - - Este archivo contiene dos usos distintos de Map: - - 1. Variable: static const List> _steps - - * Propósito: Define los pasos en el asistente de creación de perfiles. - * Estructura de cada elemento: - 1 { - 2 'id': String, - 3 'title': String, - 4 'icon': IconData - 5 } - - 2. Argumento de Función: El Map anónimo pasado a mockService.createWorkerProfile({ ... }) - - * Propósito: Recopilar y enviar los datos del perfil del nuevo usuario al servicio (en este caso, un mock). - * Estructura: - - 1 { - 2 'full_name': String, - 3 'bio': String, - 4 'preferred_locations': List, - 5 'max_distance_miles': double, - 6 'skills': List, - 7 'industries': List - 8 } - - --- - - Siguiente archivo: lib/screens/worker/worker_profile_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../worker_profile_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Claro, aquí está el análisis del archivo. - - --- - - lib/screens/worker/worker_profile_screen.dart - - Este archivo contiene dos variables Map para datos de simulación (mock). - - 1. Variable: final Map _user - - * Propósito: Almacena los datos básicos de identificación del usuario para mostrarlos en la pantalla de perfil. - * Estructura: - 1 { - 2 'full_name': String, - 3 'email': String, - 4 } - - 2. Variable: final Map _profile - - * Propósito: Almacena estadísticas y atributos detallados del trabajador para mostrarlos en la pantalla de perfil. - * Estructura: - - 1 { - 2 'level': String, - 3 'photo_url': String?, - 4 'total_shifts': int, - 5 'average_rating': double, - 6 'on_time_rate': int, - 7 'no_show_count': int, - 8 'cancellation_count': int, - 9 'reliability_score': int, - 10 'phone': String, - 11 'skills': List, // Mockeado como una lista vacía - 12 } - - --- - - Siguiente archivo: lib/screens/worker/benefits_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../worker/benefits_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ De acuerdo, aquí está el análisis del siguiente archivo. - - --- - - lib/screens/worker/benefits_screen.dart - - Este archivo utiliza Map para gestionar los datos de los beneficios del trabajador. - - 1. Variable: final List> _benefitsData - - * Propósito: Contiene los datos de simulación (mock) para los diferentes beneficios del trabajador, como días de enfermedad y vacaciones. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'title': String, - 4 'current': int, - 5 'total': int, - 6 'color': Color, - 7 'description': String, - 8 'history': List>, // <- Lista anidada - 9 'requestLabel': String, - 10 'notice': String?, // Opcional - 11 } - * Estructura anidada de `history`: - 1 { - 2 'date': String, - 3 'status': String - 4 } - - 2. Parámetro de Función: void _handleRequest(Map benefit) - - * Propósito: Maneja la acción cuando un usuario solicita un beneficio, tomando uno de los objetos Map de _benefitsData como entrada. - * Estructura: La misma que la de los elementos en _benefitsData. - - 3. Parámetro de Widget: final Map benefit (en _BenefitCard) - - * Propósito: El widget _BenefitCard utiliza un Map de _benefitsData para mostrar los detalles de un beneficio. - * Estructura: La misma que la de los elementos en _benefitsData. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/compliance/documents_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../documents_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/compliance/documents_screen.dart - - Este archivo, similar a otros, usa Map para la gestión de datos de UI. - - 1. Variable: final List> _requiredDocs - - * Propósito: Almacena la lista de documentos de cumplimiento requeridos para el trabajador. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'name': String, - 4 'description': String, - 5 'status': String // Ejemplo: 'verified', 'pending', 'missing' - 6 } - - 2. Parámetro de Función: Widget _buildDocumentCard(Map doc) - - * Propósito: Es una función de construcción que crea una tarjeta de UI para un solo documento, tomando como entrada un Map de la lista _requiredDocs. - * Estructura: La estructura del parámetro doc es la misma que la de los elementos en la lista _requiredDocs. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile l/.../emergency_contact_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart - - Este archivo gestiona los contactos de emergencia del trabajador. - - 1. Variable: final List> _contacts - - * Propósito: Almacena una lista de los contactos de emergencia del trabajador. - * Estructura de cada elemento: - - 1 { - 2 'name': String, - 3 'phone': String, - 4 'relationship': String // Ejemplo: 'family', 'spouse', 'friend', 'other' - 5 } - - 2. Parámetro de Función: Widget _buildContactForm(int index, Map contact) - - * Propósito: Es una función de construcción que toma un Map de un solo contacto de la lista _contacts para crear un formulario para ese contacto. - * Estructura: La estructura del parámetro contact es la misma que la de los elementos en la lista _contacts. - - 3. Parámetro de Función: void _updateContact(int index, String field, dynamic value) - - * Propósito: Esta función actualiza un campo dentro de un Map de contacto específico en la lista _contacts. El value es dynamic ya que puede ser un String de un TextField o de un - DropdownButton. - * Estructura: No tiene una estructura de mapa específica, pero opera sobre los mapas dentro de la lista _contacts. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/compliance/certificates_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../certificates_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Okay, aquí está el análisis del archivo certificates_screen.dart. - - --- - - lib/screens/worker/worker_profile/compliance/certificates_screen.dart - - Este archivo maneja los certificados de cumplimiento del trabajador. - - 1. Variable: final List> _certificates - - * Propósito: Almacena una lista de los certificados de cumplimiento del trabajador (por ejemplo, verificación de antecedentes, manipulador de alimentos). - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'name': String, - 4 'icon': IconData, - 5 'color': Color, - 6 'description': String, - 7 'status': String, // Ejemplo: 'complete', 'expiring', 'not_started' - 8 'expiry': String?, // Cadena de fecha ISO 8601 que puede ser nula - 9 } - - 2. Parámetro de Función: Widget _buildCertificateCard(Map cert) - - * Propósito: Es una función de construcción que crea una tarjeta de UI para un solo certificado, tomando como entrada un Map de la lista _certificates. - * Estructura: La estructura del parámetro cert es la misma que la de los elementos en _certificates. - - 3. Parámetro de Función: void _showUploadModal(BuildContext context, Map? cert) - - * Propósito: Esta función muestra una hoja modal para subir un certificado. Acepta un Map opcional cert. Si se proporciona cert, el modal es para renovar o ver ese certificado específico. - Si es null, es para subir un nuevo certificado sin categoría. - * Estructura: La estructura del parámetro cert es la misma que la de los elementos en _certificates. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/compliance/tax_forms_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../tax_forms_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/compliance/tax_forms_screen.dart - - Este archivo gestiona la lista de formularios de impuestos del trabajador. - - 1. Variable: final List> _forms - - * Propósito: Almacena una lista de los formularios de impuestos requeridos. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'title': String, - 4 'subtitle': String, - 5 'description': String, - 6 'status': String, // Ejemplo: 'submitted', 'not_started' - 7 'icon': String, // Un emoji usado como icono - 8 } - - 2. Parámetro de Función: Widget _buildFormCard(Map form) - - * Propósito: Es una función de construcción que crea una tarjeta de UI para un solo formulario de impuestos, tomando como entrada un Map de la lista _forms. - * Estructura: La estructura del parámetro form es la misma que la de los elementos en la lista _forms. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/onboarding/personal_info_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../personal_info_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/onboarding/personal_info_screen.dart - - Este archivo contiene los datos de simulación (mock) para el formulario de información personal. - - 1. Variable: final Map _user - - * Propósito: Almacena los datos básicos del usuario para mostrarlos en el formulario. - * Estructura: - - 1 { - 2 'full_name': String, - 3 'email': String, - 4 'photo_url': String?, // Admite valores nulos - 5 } - * Nota: Esta versión del mock _user es ligeramente diferente a la de worker_profile_screen.dart, ya que incluye el campo photo_url. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/onboarding/attire_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../attire_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/onboarding/attire_screen.dart - - Este archivo maneja el "armario" o la vestimenta que posee el trabajador. - - 1. Variable: final List> _attireOptions - - * Propósito: Proporciona una lista de opciones de vestimenta seleccionables para el trabajador. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'label': String, - 4 'icon': IconData, - 5 'imageUrl': String, - 6 } - - (Nota: Este archivo también contiene `Map` y `Map` para la gestión del estado, pero no coinciden con el tipo `Map`). - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../form_i9_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart - - Este archivo contiene el formulario I-9 y utiliza mapas para gestionar los datos del formulario y los pasos del asistente. - - 1. Variable: final Map _formData - - * Propósito: Almacena el estado de los campos del formulario I-9 mientras el usuario los completa. - * Estructura: - - 1 { - 2 'lastName': String, - 3 'firstName': String, - 4 'middleInitial': String, - 5 'otherLastNames': String, - 6 'address': String, - 7 'aptNumber': String, - 8 'city': String, - 9 'state': String?, // Admite valores nulos - 10 'zipCode': String, - 11 'dateOfBirth': String, - 12 'ssn': String, - 13 'email': String, - 14 'phone': String, - 15 'citizenshipStatus': String, - 16 'uscisNumber': String, - 17 'i94Number': String, - 18 'foreignPassportNumber': String, - 19 'countryOfIssuance': String, - 20 'expirationDate': String, - 21 } - - 2. Variable: final List> _steps - - * Nota: Aunque este no es un Map, sigue un patrón similar. - * Propósito: Define los pasos del asistente del formulario I-9. - * Estructura de cada elemento: - 1 { - 2 'title': String, - 3 'subtitle': String, - 4 } - - 3. Parámetro de Función: void _updateField(String key, dynamic value) - - * Propósito: Esta función actualiza un campo en el mapa _formData. El value es dynamic porque puede ser un String de un TextField o de un DropdownButton. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../form_w4_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Claro, aquí tienes el análisis. - - --- - - lib/screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart - - Este archivo contiene el formulario W-4 y, de manera similar al I-9, utiliza mapas para gestionar los datos. - - 1. Variable: final Map _formData - - * Propósito: Almacena el estado de los campos del formulario W-4 mientras el usuario los completa. - * Estructura: - - 1 { - 2 'firstName': String, - 3 'lastName': String, - 4 'address': String, - 5 'cityStateZip': String, - 6 'ssn': String, - 7 'filingStatus': String, - 8 'multipleJobs': bool, - 9 'qualifyingChildren': int, - 10 'otherDependents': int, - 11 'otherIncome': String, // Representa una cantidad en dólares - 12 'deductions': String, // Representa una cantidad en dólares - 13 'extraWithholding': String, // Representa una cantidad en dólares - 14 } - - 2. Variable: final List> _steps - - * Nota: Aunque este es un List>, sigue un patrón de uso de mapas para definir metadatos. - * Propósito: Define los pasos del asistente del formulario W-4. - * Estructura de cada elemento: - 1 { - 2 'title': String, - 3 'subtitle': String, - 4 } - - 3. Parámetro de Función: void _updateField(String key, dynamic value) - - * Propósito: Esta función actualiza un campo en el mapa _formData. El value es dynamic porque puede ser un String, bool, o int dependiendo del campo del formulario que se esté - actualizando. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/level_up/trainings_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../trainings_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ De acuerdo. - - --- - - lib/screens/worker/worker_profile/level_up/trainings_screen.dart - - Este archivo contiene la lista de cursos de capacitación para los trabajadores. - - 1. Variable: final List> _courses - - * Propósito: Almacena una lista de los cursos de capacitación disponibles. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'title': String, - 4 'description': String, - 5 'duration_minutes': int, - 6 'xp_reward': int, - 7 'thumbnail_url': String?, // Admite valores nulos - 8 'progress_percent': int, - 9 'completed': bool, - 10 } - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/finances/time_card_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../time_card_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Okay, analicemos este archivo. - - --- - - lib/screens/worker/worker_profile/finances/time_card_screen.dart - - Este archivo se utiliza para mostrar el historial de horas trabajadas del empleado. - - 1. Variable: final List> _timesheets - - * Propósito: Almacena una lista de registros de hojas de tiempo (timesheets) para los turnos trabajados. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'shift_id': String, - 4 'date': String, // Cadena en formato ISO 8601 - 5 'actual_start': String, - 6 'actual_end': String, - 7 'total_hours': double, - 8 'hourly_rate': double, - 9 'total_pay': double, - 10 'status': String, // Ejemplo: 'pending', 'approved', 'paid' - 11 'shift_title': String, - 12 'client_name': String, - 13 'location': String, - 14 } - - 2. Parámetro de Función: Widget _buildShiftHistory(List> timesheets) - - * Propósito: Es una función de construcción que toma una lista de mapas de hojas de tiempo para renderizar la sección de historial. - * Estructura: La estructura del parámetro timesheets es una lista de mapas, donde cada mapa tiene la misma estructura que los elementos en _timesheets. - - 3. Parámetro de Función: Widget _buildTimesheetCard(Map timesheet) - - * Propósito: Es una función de construcción que crea una tarjeta de UI para un único registro de hoja de tiempo de la lista _timesheets. - * Estructura: La estructura del parámetro timesheet es la misma que la de los elementos en _timesheets. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/support/faqs_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../support/faqs_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/support/faqs_screen.dart - - Este archivo contiene los datos para la pantalla de Preguntas Frecuentes (FAQs). - - 1. Variable: final List> _faqData - - * Propósito: Almacena los datos para las preguntas frecuentes, organizados por categoría. - * Estructura de cada elemento (categoría): - - 1 { - 2 'category': String, - 3 'questions': List>, // <- Lista anidada - 4 } - * Estructura anidada de `questions`: - 1 { - 2 'q': String, // La pregunta - 3 'a': String, // La respuesta - 4 } - - (Nota: Este archivo también contiene un `Map` llamado `_openItems` para gestionar el estado de la UI, pero no coincide con el tipo `Map`). - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/level_up/krow_university_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../krow_university_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/level_up/krow_university_screen.dart - - Este archivo es para la sección de "KROW University" y contiene varios usos de Map. - - 1. Variable: final Map _profile - - * Propósito: Almacena un subconjunto de los datos del perfil del trabajador que son relevantes para la sección de universidad/capacitación. - * Estructura: - - 1 { - 2 'level': String, - 3 'xp': int, - 4 'nextLevelXp': int, - 5 'completed_courses': int, - 6 } - * Nota: Este mapa _profile es inconsistente con el que se encuentra en worker_profile_screen.dart, lo que demuestra la necesidad de un modelo de datos unificado. - - 2. Variable: final List> _categories - - * Propósito: Define las categorías para los cursos de la universidad. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'label': String, - 4 'icon': IconData, - 5 } - - 3. Variable: final List> _courses - - * Propósito: Almacena una lista de los cursos universitarios disponibles. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'title': String, - 4 'description': String, - 5 'category': String, - 6 'duration_minutes': int, - 7 'xp_reward': int, - 8 'level_required': String, - 9 'is_certification': bool, - 10 'progress_percent': int, - 11 'completed': bool, - 12 } - - 4. Parámetro de Función: Widget _buildCoursesGrid(List> courses) - - * Propósito: Es una función de construcción que toma una lista de mapas de cursos (filtrados de _courses) para renderizarlos en una cuadrícula. - * Estructura: La estructura del parámetro courses es una lista de mapas, donde cada mapa tiene la misma estructura que los elementos en _courses. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../leaderboard_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos con el siguiente archivo. - - --- - - lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart - - Este archivo es para la pantalla de la tabla de clasificación (Leaderboard) y utiliza mapas extensivamente para manejar los datos de los perfiles. - - 1. Variable: final List> _profiles - - * Propósito: Almacena los datos de simulación (mock) para la tabla de clasificación, representando diferentes perfiles de trabajadores. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'name': String, - 4 'photo_url': String?, // Admite valores nulos - 5 'xp': int, - 6 'level': String, - 7 'user_id': String, - 8 } - - 2. Variable: final sortedProfiles = List>.from(_profiles) - - * Propósito: Crea una copia mutable de la lista _profiles que puede ser ordenada por XP. - * Estructura: Los elementos tienen la misma estructura que en _profiles. - - 3. Parámetro de Función: Widget _buildPodium(List> topThree) - - * Propósito: Es una función de construcción que toma los tres perfiles principales para renderizar la sección del podio. - * Estructura: La lista topThree contiene mapas con la misma estructura que en _profiles. - - 4. Parámetro de Función: Widget _buildPodiumItem(Map profile, ...) - - * Propósito: Es una función de construcción para crear la UI de un solo perfil en el podio. - * Estructura: El parámetro profile tiene la misma estructura que un elemento en _profiles. - - 5. Parámetro de Función: Widget _buildRestList(List> rest, ...) - - * Propósito: Es una función de construcción que toma el resto de los perfiles (que no están en el top tres) para renderizarlos como una lista estándar. - * Estructura: La lista rest contiene mapas con la misma estructura que en _profiles. - - --- - - Siguiente archivo: lib/screens/worker/worker_profile/finances/bank_account_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../bank_account_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/worker_profile/finances/bank_account_screen.dart - - Este archivo maneja las cuentas bancarias del trabajador. - - 1. Variable: final List> _accounts - - * Propósito: Almacena una lista de las cuentas bancarias vinculadas del trabajador. - * Estructura de cada elemento: - - 1 { - 2 'id': int, - 3 'bank': String, - 4 'type': String, // Ejemplo: 'Checking', 'Savings' - 5 'last4': String, - 6 'isPrimary': bool, - 7 } - - 2. Parámetro de Función: Widget _buildAccountCard(Map account) - - * Propósito: Es una función de construcción que crea una tarjeta de UI para una sola cuenta bancaria, tomando como entrada un Map de la lista _accounts. - * Estructura: La estructura del parámetro account es la misma que la de los elementos en la lista _accounts. - - --- - - Siguiente archivo: lib/screens/worker/payments_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../worker/payments_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Sigamos. - - --- - - lib/screens/worker/payments_screen.dart - - Este archivo muestra el historial de pagos y ganancias del trabajador. - - 1. Variable: final List> _recentPayments - - * Propósito: Almacena los datos de simulación (mock) para una lista de registros de pagos recientes. - * Estructura de cada elemento: - - 1 { - 2 'date': String, - 3 'title': String, - 4 'location': String, - 5 'address': String, - 6 'workedTime': String, - 7 'amount': double, - 8 'status': String, // Ejemplo: 'paid' - 9 'hours': int, - 10 'rate': int, // Nota: Esto es un int en el mock, pero probablemente debería ser double como en otros lugares. - 11 } - * Nota: El widget PaymentHistoryItem que consume estos datos espera que rate sea un double, por lo que el int en los datos del mock es probablemente una pequeña inconsistencia. - - --- - - Siguiente archivo: lib/screens/worker/availability_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../availability_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Okay, aquí está el análisis del archivo de disponibilidad. - - --- - - lib/screens/worker/availability_screen.dart - - Este archivo maneja la configuración de la disponibilidad del trabajador. - - 1. Variable: final List> _timeSlots - - * Propósito: Define las propiedades de los diferentes rangos horarios (Mañana, Tarde, Noche) que el usuario puede seleccionar. - * Estructura de cada elemento: - - 1 { - 2 'id': String, - 3 'label': String, - 4 'time': String, // Ejemplo: '4:00 AM - 12:00 PM' - 5 'icon': IconData, - 6 'bg': Color, - 7 'iconColor': Color, - 8 } - - (Nota: Este archivo también utiliza `Map` y `Map>` para gestionar el estado de la disponibilidad, pero no coinciden con el tipo `Map`). - - --- - - Siguiente archivo: lib/screens/worker/clock_in_screen.dart. -╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ -│ ✓ ReadFile lib/.../worker/clock_in_screen.dart │ -│ │ -╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -✦ Okay, aquí está el análisis del último archivo de la lista. - - --- - - lib/screens/worker/clock_in_screen.dart - - Este archivo gestiona la pantalla de fichaje (check-in/check-out) del trabajador. - - 1. Variable: final List> _recentActivity - - * Propósito: Almacena una lista de las actividades recientes de fichaje del trabajador. - * Estructura de cada elemento: - - 1 { - 2 'date': DateTime, - 3 'start': String, // Ejemplo: '09:00 AM' - 4 'end': String, // Ejemplo: '05:00 PM' - 5 'hours': String, // Ejemplo: '8h' - 6 } - - --- - - ✦ He analizado lib/screens/worker/worker_profile/support/messages_screen.dart. - - Este archivo contiene dos estructuras principales de List>: - - 1. Nombre de la variable: _conversations - * Propósito: Representa una lista de conversaciones de chat. - * Estructura de cada elemento `Map` (que representa una conversación individual): - - 1 { - 2 'sender_id': String, // ID del remitente/otra parte en la conversación - 3 'sender_name': String, // Nombre visible del remitente/otra parte - 4 'lastMessage': String, // Contenido del último mensaje en la conversación - 5 'lastTime': DateTime, // Marca de tiempo del último mensaje - 6 'unread': int, // Número de mensajes no leídos en la conversación - 7 'messages': List>, // Lista anidada de mensajes individuales dentro de la conversación - 8 } - * Estructura Anidada (`messages`): Cada elemento en la lista messages tiene: - - 1 { - 2 'content': String, // El contenido del mensaje - 3 'sender_id': String, // El ID del remitente de este mensaje específico - 4 } - - El siguiente archivo es: lib/screens/worker/worker_profile/onboarding/attire_screen.dart. - --- - - He finalizado el análisis de todos los archivos que contenían Map. Has podido ver que este tipo de mapa se usa de forma muy extendida en todo el proyecto para simular - datos, pasar parámetros y definir el estado de los widgets. - - La principal conclusión es la falta de modelos de datos formales (clases Dart), lo que lleva a la duplicación e inconsistencia de las estructuras de datos en diferentes pantallas. - - Mi recomendación principal, como ingeniero senior, sería refactorizar este código para usar clases de modelo fuertemente tipadas. Esto mejoraría enormemente la mantenibilidad, la - legibilidad y la seguridad del código, reduciendo errores a largo plazo. - - ¿Hay alguna de estas estructuras que te interese formalizar en una clase Dart ahora? O, ¿tienes alguna otra pregunta? - - Using: 1 GEMINI.md file diff --git a/apps/mobile/prototypes/staff_mobile_application/mock_staff_data_v3_update.md b/apps/mobile/prototypes/staff_mobile_application/mock_staff_data_v3_update.md deleted file mode 100644 index 33315037..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/mock_staff_data_v3_update.md +++ /dev/null @@ -1,594 +0,0 @@ -# Análisis Exhaustivo de `Map` en el Proyecto - -Este documento detalla todos los usos del tipo `Map` encontrados en los archivos `.dart` del proyecto, incluyendo variables, listas, parámetros y tipos de retorno de funciones. - ---- - -### `lib/widgets/shift_card.dart` - -#### 1. Tipo de Retorno de Función: `Map _calculateDuration()` -* **Propósito:** Calcula la duración de un turno en horas y devuelve también una cadena de texto para el tiempo de descanso. -* **Estructura del `Map` devuelto:** - ```dart - { - 'hours': int, - 'breakTime': String, - } - ``` - ---- - -### `lib/services/mock_service.dart` - -#### 1. Parámetro de Función: `Future createWorkerProfile(Map data)` -* **Propósito:** Simula la creación de un perfil de trabajador. Acepta un `Map` llamado `data` que contiene la información del perfil del nuevo trabajador. -* **Estructura Inferida (por su uso):** - ```dart - { - 'full_name': String, - 'bio': String, - 'preferred_locations': List, - 'max_distance_miles': double, - 'skills': List, - 'industries': List, - } - ``` - ---- - -### `lib/screens/auth/profile_setup_screen.dart` - -#### 1. Variable: `static const List> _steps` -* **Propósito:** Define los pasos en el asistente de creación de perfiles. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'title': String, - 'icon': IconData - } - ``` - -#### 2. Argumento de Función: (Anónimo) en `mockService.createWorkerProfile` -* **Propósito:** Recopila y envía los datos del perfil del nuevo usuario al servicio mock. -* **Estructura:** - ```dart - { - 'full_name': String, - 'bio': String, - 'preferred_locations': List, - 'max_distance_miles': double, - 'skills': List, - 'industries': List - } - ``` - ---- - -### `lib/screens/worker/benefits_screen.dart` - -#### 1. Variable: `final List> _benefitsData` -* **Propósito:** Contiene los datos de simulación (mock) para los diferentes beneficios del trabajador. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'title': String, - 'current': int, - 'total': int, - 'color': Color, - 'description': String, - 'history': List>, // <- Lista anidada - 'requestLabel': String, - 'notice': String?, - } - ``` - * **Estructura anidada de `history`:** - ```dart - { - 'date': String, - 'status': String - } - ``` - -#### 2. Parámetro de Función: `void _handleRequest(Map benefit)` -* **Propósito:** Maneja la acción cuando un usuario solicita un beneficio. -* **Estructura:** La misma que los elementos de `_benefitsData`. - -#### 3. Parámetro de Widget: `final Map benefit` -* **Propósito:** El widget `_BenefitCard` recibe un `Map` para mostrar los detalles de un beneficio. -* **Estructura:** La misma que los elementos de `_benefitsData`. - ---- - -### `lib/screens/worker/worker_profile_screen.dart` - -#### 1. Variable: `final Map _user` -* **Propósito:** Almacena datos básicos de identificación del usuario. -* **Estructura:** - ```dart - { - 'full_name': String, - 'email': String, - } - ``` - -#### 2. Variable: `final Map _profile` -* **Propósito:** Almacena estadísticas y atributos detallados del perfil del trabajador. -* **Estructura:** - ```dart - { - 'level': String, - 'photo_url': String?, - 'total_shifts': int, - 'average_rating': double, - 'on_time_rate': int, - 'no_show_count': int, - 'cancellation_count': int, - 'reliability_score': int, - 'phone': String, - 'skills': List, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart` - -#### 1. Variable: `final List> _contacts` -* **Propósito:** Almacena una lista de los contactos de emergencia. -* **Estructura de cada elemento:** - ```dart - { - 'name': String, - 'phone': String, - 'relationship': String - } - ``` - -#### 2. Parámetro de Función: `Widget _buildContactForm(int index, Map contact)` -* **Propósito:** Construye el widget del formulario para un contacto. -* **Estructura:** La misma que los elementos de `_contacts`. - ---- - -### `lib/screens/worker/worker_profile/onboarding/personal_info_screen.dart` - -#### 1. Variable: `final Map _user` -* **Propósito:** Almacena los datos básicos del usuario para el formulario. -* **Estructura:** - ```dart - { - 'full_name': String, - 'email': String, - 'photo_url': String?, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/finances/time_card_screen.dart` - -#### 1. Variable: `final List> _timesheets` -* **Propósito:** Almacena una lista de registros de hojas de tiempo (timesheets). -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'shift_id': String, - 'date': String, // ISO 8601 - 'actual_start': String, - 'actual_end': String, - 'total_hours': double, - 'hourly_rate': double, - 'total_pay': double, - 'status': String, - 'shift_title': String, - 'client_name': String, - 'location': String, - } - ``` - -#### 2. Parámetro de Función: `Widget _buildShiftHistory(List> timesheets)` -* **Propósito:** Construye la sección de historial de turnos. -* **Estructura:** Una lista donde cada elemento tiene la estructura de `_timesheets`. - -#### 3. Parámetro de Función: `Widget _buildTimesheetCard(Map timesheet)` -* **Propósito:** Construye la tarjeta para una sola hoja de tiempo. -* **Estructura:** La misma que los elementos de `_timesheets`. - ---- - -### `lib/screens/worker/worker_profile/finances/bank_account_screen.dart` - -#### 1. Variable: `final List> _accounts` -* **Propósito:** Almacena una lista de las cuentas bancarias vinculadas. -* **Estructura de cada elemento:** - ```dart - { - 'id': int, - 'bank': String, - 'type': String, - 'last4': String, - 'isPrimary': bool, - } - ``` - -#### 2. Parámetro de Función: `Widget _buildAccountCard(Map account)` -* **Propósito:** Construye la tarjeta para una sola cuenta bancaria. -* **Estructura:** La misma que los elementos de `_accounts`. - ---- - -### `lib/screens/worker/worker_profile/level_up/trainings_screen.dart` - -#### 1. Variable: `final List> _courses` -* **Propósito:** Almacena una lista de cursos de capacitación. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'title': String, - 'description': String, - 'duration_minutes': int, - 'xp_reward': int, - 'thumbnail_url': String?, - 'progress_percent': int, - 'completed': bool, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart` - -#### 1. Variable: `final List> _profiles` -* **Propósito:** Almacena los datos de los perfiles para la tabla de clasificación. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'name': String, - 'photo_url': String?, - 'xp': int, - 'level': String, - 'user_id': String, - } - ``` - -#### 2. Variable: `final sortedProfiles = List>.from(_profiles)` -* **Propósito:** Crea una copia mutable de la lista de perfiles para ordenarla. -* **Estructura:** Los elementos tienen la misma estructura que `_profiles`. - -#### 3. Parámetro de Función: `Widget _buildPodium(List> topThree)` -* **Propósito:** Construye la sección del podio con los 3 mejores perfiles. -* **Estructura:** Una lista donde cada mapa tiene la estructura de un elemento de `_profiles`. - -#### 4. Parámetro de Función: `Map profile` (en `_buildPodiumItem`) -* **Propósito:** Construye el item para un perfil en el podio. -* **Estructura:** La misma que un elemento de `_profiles`. - -#### 5. Parámetro de Función: `Widget _buildRestList(List> rest, ...)` -* **Propósito:** Construye la lista para el resto de los perfiles. -* **Estructura:** Una lista donde cada mapa tiene la estructura de un elemento de `_profiles`. - ---- - -### `lib/screens/worker/worker_profile/onboarding/attire_screen.dart` - -#### 1. Variable: `final List> _attireOptions` -* **Propósito:** Define las opciones de vestimenta que un trabajador puede seleccionar. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'label': String, - 'icon': IconData, - 'imageUrl': String, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/support/faqs_screen.dart` - -#### 1. Variable: `final List> _faqData` -* **Propósito:** Almacena los datos de las preguntas frecuentes, organizados por categoría. -* **Estructura de cada elemento (categoría):** - ```dart - { - 'category': String, - 'questions': List>, // <- Lista anidada - } - ``` - * **Estructura anidada de `questions`:** - ```dart - { - 'q': String, // Pregunta - 'a': String, // Respuesta - } - ``` - ---- - -### `lib/screens/worker/worker_profile/support/messages_screen.dart` - -#### 1. Variable: `final List> _conversations` -* **Propósito:** Contiene los datos de simulación para las conversaciones de chat. -* **Estructura de cada elemento (conversación):** - ```dart - { - 'sender_id': String, - 'sender_name': String, - 'lastMessage': String, - 'lastTime': DateTime, - 'unread': int, - 'messages': List>, // <- Lista anidada - } - ``` - * **Estructura anidada de `messages`:** - ```dart - { - 'content': String, - 'sender_id': String, - } - ``` - -#### 2. Variable: `Map? _selectedChat` -* **Propósito:** Almacena la conversación que el usuario ha seleccionado para ver. -* **Estructura:** La misma que un elemento de `_conversations`. - ---- - -### `lib/screens/worker/payments_screen.dart` - -#### 1. Variable: `final List> _recentPayments` -* **Propósito:** Almacena registros detallados de pagos recientes. -* **Estructura de cada elemento:** - ```dart - { - 'date': String, - 'title': String, - 'location': String, - 'address': String, - 'workedTime': String, - 'amount': double, - 'status': String, - 'hours': int, - 'rate': int, // Debería ser double - } - ``` - ---- - -### `lib/screens/worker/worker_profile/compliance/documents_screen.dart` - -#### 1. Variable: `final List> _requiredDocs` -* **Propósito:** Almacena la lista de documentos de cumplimiento requeridos. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'name': String, - 'description': String, - 'status': String, - } - ``` - -#### 2. Parámetro de Función: `Widget _buildDocumentCard(Map doc)` -* **Propósito:** Construye la tarjeta de UI para un solo documento. -* **Estructura:** La misma que los elementos de `_requiredDocs`. - ---- - -### `lib/screens/worker/worker_profile/compliance/tax_forms_screen.dart` - -#### 1. Variable: `final List> _forms` -* **Propósito:** Almacena la lista de formularios de impuestos. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'title': String, - 'subtitle': String, - 'description': String, - 'status': String, - 'icon': String, // Emoji - } - ``` - -#### 2. Parámetro de Función: `Widget _buildFormCard(Map form)` -* **Propósito:** Construye la tarjeta de UI para un solo formulario. -* **Estructura:** La misma que los elementos de `_forms`. - ---- - -### `lib/screens/worker/availability_screen.dart` - -#### 1. Variable: `final List> _timeSlots` -* **Propósito:** Define las propiedades de los diferentes rangos horarios para la disponibilidad. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'label': String, - 'time': String, - 'icon': IconData, - 'bg': Color, - 'iconColor': Color, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/compliance/certificates_screen.dart` - -#### 1. Variable: `final List> _certificates` -* **Propósito:** Almacena la lista de certificados de cumplimiento del trabajador. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'name': String, - 'icon': IconData, - 'color': Color, - 'description': String, - 'status': String, - 'expiry': String?, // ISO 8601 - } - ``` - -#### 2. Parámetro de Función: `Widget _buildCertificateCard(Map cert)` -* **Propósito:** Construye la tarjeta de UI para un solo certificado. -* **Estructura:** La misma que los elementos de `_certificates`. - -#### 3. Parámetro de Función: `void _showUploadModal(BuildContext context, Map? cert)` -* **Propósito:** Muestra un modal para subir un certificado. -* **Estructura:** La misma que los elementos de `_certificates`. - ---- - -### `lib/screens/worker/worker_profile/compliance/taxforms/form_i9_screen.dart` - -#### 1. Variable: `final Map _formData` -* **Propósito:** Almacena el estado de los campos del formulario I-9. -* **Estructura:** - ```dart - { - 'lastName': String, - 'firstName': String, - 'middleInitial': String, - 'otherLastNames': String, - 'address': String, - 'aptNumber': String, - 'city': String, - 'state': String?, - 'zipCode': String, - 'dateOfBirth': String, - 'ssn': String, - 'email': String, - 'phone': String, - 'citizenshipStatus': String, - 'uscisNumber': String, - 'i94Number': String, - 'foreignPassportNumber': String, - 'countryOfIssuance': String, - 'expirationDate': String, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/compliance/taxforms/form_w4_screen.dart` - -#### 1. Variable: `final Map _formData` -* **Propósito:** Almacena el estado de los campos del formulario W-4. -* **Estructura:** - ```dart - { - 'firstName': String, - 'lastName': String, - 'address': String, - 'cityStateZip': String, - 'ssn': String, - 'filingStatus': String, - 'multipleJobs': bool, - 'qualifyingChildren': int, - 'otherDependents': int, - 'otherIncome': String, - 'deductions': String, - 'extraWithholding': String, - } - ``` - ---- - -### `lib/screens/worker/worker_profile/level_up/krow_university_screen.dart` - -#### 1. Variable: `final Map _profile` -* **Propósito:** Almacena un subconjunto de datos del perfil relevantes para la universidad. -* **Estructura:** - ```dart - { - 'level': String, - 'xp': int, - 'badges': List, - } - ``` - -#### 2. Variable: `final List> _levels` -* **Propósito:** Define los diferentes niveles de Krower y sus propiedades. -* **Estructura de cada elemento:** - ```dart - { - 'name': String, - 'xpRequired': int, - 'icon': IconData, - 'colors': List, - } - ``` - -#### 3. Variable: `final List> _categories` -* **Propósito:** Define las categorías para los cursos. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'label': String, - 'icon': IconData, - } - ``` - -#### 4. Variable: `final List> _courses` -* **Propósito:** Almacena la lista de cursos disponibles. -* **Estructura de cada elemento:** - ```dart - { - 'id': String, - 'title': String, - 'description': String, - 'category': String, - 'duration_minutes': int, - 'xp_reward': int, - 'level_required': String, - 'is_certification': bool, - 'progress_percent': int, - 'completed': bool, - } - ``` - -#### 5. Parámetro de Función: `Widget _buildCoursesList(List> courses)` -* **Propósito:** Construye la lista de widgets de cursos. -* **Estructura:** Una lista donde cada mapa tiene la estructura de un elemento de `_courses`. - ---- - -### `lib/screens/worker/earnings_screen.dart` - -#### 1. Variable: `final List> _recentPayments` -* **Propósito:** Almacena resúmenes de pagos recientes. -* **Estructura de cada elemento:** - ```dart - { - 'date': String, - 'amount': double, - 'shifts': int, - 'status': String, - } - ``` - ---- - -### `lib/screens/worker/clock_in_screen.dart` - -#### 1. Variable: `final List> _recentActivity` -* **Propósito:** Almacena una lista de actividades recientes de fichaje. -* **Estructura de cada elemento:** - ```dart - { - 'date': DateTime, - 'start': String, - 'end': String, - 'hours': String, - } - ``` diff --git a/apps/mobile/prototypes/staff_mobile_application/pubspec.lock b/apps/mobile/prototypes/staff_mobile_application/pubspec.lock deleted file mode 100644 index 754381ac..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/pubspec.lock +++ /dev/null @@ -1,786 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d - url: "https://pub.dev" - source: hosted - version: "91.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 - url: "https://pub.dev" - source: hosted - version: "8.4.1" - archive: - dependency: transitive - description: - name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" - url: "https://pub.dev" - source: hosted - version: "4.0.7" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.dev" - source: hosted - version: "2.0.4" - cli_config: - dependency: transitive - description: - name: cli_config - sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec - url: "https://pub.dev" - source: hosted - version: "0.2.0" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - coverage: - dependency: transitive - description: - name: coverage - sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" - url: "https://pub.dev" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" - source: hosted - version: "3.0.7" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - firebase_core: - dependency: "direct main" - description: - name: firebase_core - sha256: "1f2dfd9f535d81f8b06d7a50ecda6eac1e6922191ed42e09ca2c84bd2288927c" - url: "https://pub.dev" - source: hosted - version: "4.2.1" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 - url: "https://pub.dev" - source: hosted - version: "6.0.2" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: ff18fabb0ad0ed3595d2f2c85007ecc794aadecdff5b3bb1460b7ee47cded398 - url: "https://pub.dev" - source: hosted - version: "3.3.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_launcher_icons: - dependency: "direct dev" - description: - name: flutter_launcher_icons - sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" - url: "https://pub.dev" - source: hosted - version: "0.14.4" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_riverpod: - dependency: "direct main" - description: - name: flutter_riverpod - sha256: "9e2d6907f12cc7d23a846847615941bddee8709bf2bfd274acdf5e80bcf22fde" - url: "https://pub.dev" - source: hosted - version: "3.0.3" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - font_awesome_flutter: - dependency: "direct main" - description: - name: font_awesome_flutter - sha256: b9011df3a1fa02993630b8fb83526368cf2206a711259830325bab2f1d2a4eb0 - url: "https://pub.dev" - source: hosted - version: "10.12.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: c92d18e1fe994cb06d48aa786c46b142a5633067e8297cff6b5a3ac742620104 - url: "https://pub.dev" - source: hosted - version: "17.0.0" - google_fonts: - dependency: "direct main" - description: - name: google_fonts - sha256: ba03d03bcaa2f6cb7bd920e3b5027181db75ab524f8891c8bc3aa603885b8055 - url: "https://pub.dev" - source: hosted - version: "6.3.3" - http: - dependency: transitive - description: - name: http - sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image: - dependency: transitive - description: - name: image - sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" - url: "https://pub.dev" - source: hosted - version: "4.5.4" - intl: - dependency: "direct main" - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" - source: hosted - version: "0.7.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - lucide_icons: - dependency: "direct main" - description: - name: lucide_icons - sha256: ad24d0fd65707e48add30bebada7d90bff2a1bba0a72d6e9b19d44246b0e83c4 - url: "https://pub.dev" - source: hosted - version: "0.257.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" - source: hosted - version: "1.17.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - node_preamble: - dependency: transitive - description: - name: node_preamble - sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - package_config: - dependency: transitive - description: - name: package_config - sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.dev" - source: hosted - version: "2.2.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" - source: hosted - version: "2.2.22" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" - url: "https://pub.dev" - source: hosted - version: "2.5.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" - url: "https://pub.dev" - source: hosted - version: "7.0.1" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pool: - dependency: transitive - description: - name: pool - sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" - url: "https://pub.dev" - source: hosted - version: "1.5.2" - posix: - dependency: transitive - description: - name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" - url: "https://pub.dev" - source: hosted - version: "6.0.3" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - riverpod: - dependency: transitive - description: - name: riverpod - sha256: c406de02bff19d920b832bddfb8283548bfa05ce41c59afba57ce643e116aa59 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - source_maps: - dependency: transitive - description: - name: source_maps - sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" - url: "https://pub.dev" - source: hosted - version: "0.10.13" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - state_notifier: - dependency: transitive - description: - name: state_notifier - sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb - url: "https://pub.dev" - source: hosted - version: "1.0.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test: - dependency: transitive - description: - name: test - sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" - url: "https://pub.dev" - source: hosted - version: "1.26.3" - test_api: - dependency: transitive - description: - name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 - url: "https://pub.dev" - source: hosted - version: "0.7.7" - test_core: - dependency: transitive - description: - name: test_core - sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" - url: "https://pub.dev" - source: hosted - version: "0.6.12" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" - watcher: - dependency: transitive - description: - name: watcher - sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a" - url: "https://pub.dev" - source: hosted - version: "1.1.4" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - webkit_inspection_protocol: - dependency: transitive - description: - name: webkit_inspection_protocol - sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" - source: hosted - version: "6.6.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.10.0 <4.0.0" - flutter: ">=3.35.0" diff --git a/apps/mobile/prototypes/staff_mobile_application/pubspec.yaml b/apps/mobile/prototypes/staff_mobile_application/pubspec.yaml deleted file mode 100644 index 0328bd47..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/pubspec.yaml +++ /dev/null @@ -1,105 +0,0 @@ -name: staff_app_mvp -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+8 - -environment: - sdk: ^3.10.0 - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - go_router: ^17.0.0 - flutter_riverpod: ^3.0.3 - google_fonts: ^6.3.3 - intl: ^0.20.2 - lucide_icons: ^0.257.0 - flutter_svg: ^2.2.3 - firebase_core: ^4.2.1 - font_awesome_flutter: ^10.12.0 - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^6.0.0 - flutter_launcher_icons: ^0.14.4 - -flutter_launcher_icons: - android: true - ios: true - image_path: "assets/logo.png" - remove_alpha_ios: true - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - assets: - - assets/logo.png - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package diff --git a/apps/mobile/prototypes/staff_mobile_application/test/widget_test.dart b/apps/mobile/prototypes/staff_mobile_application/test/widget_test.dart deleted file mode 100644 index eed566dc..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:staff_app_mvp/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/web/favicon.png b/apps/mobile/prototypes/staff_mobile_application/web/favicon.png deleted file mode 100644 index 8aaa46ac..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/web/favicon.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-192.png b/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-192.png deleted file mode 100644 index b749bfef..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-192.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-512.png b/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48d..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-512.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-maskable-192.png b/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-maskable-512.png b/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c5669..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/web/index.html b/apps/mobile/prototypes/staff_mobile_application/web/index.html deleted file mode 100644 index e8e0cbe6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/web/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - staff_app_mvp - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/web/manifest.json b/apps/mobile/prototypes/staff_mobile_application/web/manifest.json deleted file mode 100644 index 731a5af0..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "staff_app_mvp", - "short_name": "staff_app_mvp", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/.gitignore b/apps/mobile/prototypes/staff_mobile_application/windows/.gitignore deleted file mode 100644 index d492d0d9..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/CMakeLists.txt b/apps/mobile/prototypes/staff_mobile_application/windows/CMakeLists.txt deleted file mode 100644 index 3f897296..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/CMakeLists.txt +++ /dev/null @@ -1,108 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(staff_app_mvp LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "staff_app_mvp") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(VERSION 3.14...3.25) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/CMakeLists.txt b/apps/mobile/prototypes/staff_mobile_application/windows/flutter/CMakeLists.txt deleted file mode 100644 index 903f4899..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# Set fallback configurations for older versions of the flutter tool. -if (NOT DEFINED FLUTTER_TARGET_PLATFORM) - set(FLUTTER_TARGET_PLATFORM "windows-x64") -endif() - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - ${FLUTTER_TARGET_PLATFORM} $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugin_registrant.cc b/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 1a82e7d0..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,14 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - FirebaseCorePluginCApiRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugin_registrant.h b/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugins.cmake b/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugins.cmake deleted file mode 100644 index fa8a39ba..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - firebase_core -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/CMakeLists.txt b/apps/mobile/prototypes/staff_mobile_application/windows/runner/CMakeLists.txt deleted file mode 100644 index 394917c0..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/Runner.rc b/apps/mobile/prototypes/staff_mobile_application/windows/runner/Runner.rc deleted file mode 100644 index 7b8a37d8..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "staff_app_mvp" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "staff_app_mvp" "\0" - VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "staff_app_mvp.exe" "\0" - VALUE "ProductName", "staff_app_mvp" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/flutter_window.cpp b/apps/mobile/prototypes/staff_mobile_application/windows/runner/flutter_window.cpp deleted file mode 100644 index 955ee303..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - // Flutter can complete the first frame before the "show window" callback is - // registered. The following call ensures a frame is pending to ensure the - // window is shown. It is a no-op if the first frame hasn't completed yet. - flutter_controller_->ForceRedraw(); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/flutter_window.h b/apps/mobile/prototypes/staff_mobile_application/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/main.cpp b/apps/mobile/prototypes/staff_mobile_application/windows/runner/main.cpp deleted file mode 100644 index e19fc556..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"staff_app_mvp", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/resource.h b/apps/mobile/prototypes/staff_mobile_application/windows/runner/resource.h deleted file mode 100644 index 66a65d1e..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/resources/app_icon.ico b/apps/mobile/prototypes/staff_mobile_application/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20ca..00000000 Binary files a/apps/mobile/prototypes/staff_mobile_application/windows/runner/resources/app_icon.ico and /dev/null differ diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/runner.exe.manifest b/apps/mobile/prototypes/staff_mobile_application/windows/runner/runner.exe.manifest deleted file mode 100644 index 153653e8..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,14 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/utils.cpp b/apps/mobile/prototypes/staff_mobile_application/windows/runner/utils.cpp deleted file mode 100644 index 3a0b4651..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/utils.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - unsigned int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length == 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/utils.h b/apps/mobile/prototypes/staff_mobile_application/windows/runner/utils.h deleted file mode 100644 index 3879d547..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/win32_window.cpp b/apps/mobile/prototypes/staff_mobile_application/windows/runner/win32_window.cpp deleted file mode 100644 index 60608d0f..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/win32_window.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} diff --git a/apps/mobile/prototypes/staff_mobile_application/windows/runner/win32_window.h b/apps/mobile/prototypes/staff_mobile_application/windows/runner/win32_window.h deleted file mode 100644 index e901dde6..00000000 --- a/apps/mobile/prototypes/staff_mobile_application/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_