commit f5a2e02839c1c57298ee931469e15994927fa8f3 Author: sridhar.r Date: Wed Jun 10 13:29:04 2026 +0530 Initial commit with clean Flutter & React codebase diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7a550fe --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# GEMINI_API_KEY: Required for Gemini AI API calls. +# AI Studio automatically injects this at runtime from user secrets. +# Users configure this via the Secrets panel in the AI Studio UI. +GEMINI_API_KEY="MY_GEMINI_API_KEY" + +# APP_URL: The URL where this applet is hosted. +# AI Studio automatically injects this at runtime with the Cloud Run service URL. +# Used for self-referential links, OAuth callbacks, and API endpoints. +APP_URL="MY_APP_URL" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd9e0a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +build/ +dist/ +coverage/ +.DS_Store +*.log +.env* +!.env.example +.antigravity/ +*.zip diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..99e3de5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "npm install && npm run dev", + "type": "node-terminal", + "request": "launch", + "command": "npm install && npm run dev" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f42c671 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "workbench.startupEditor": "readme" +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..37a03c0 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +
+GHBanner +
+ +# Run and deploy your AI Studio app + +This contains everything you need to run your app locally. +https://ai.studio/apps/35aee5a3-67fc-4ea9-87e1-f8abb0400a3b + +## Run Locally + +**Prerequisites:** Node.js + + +1. Install dependencies: + `npm install` +2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key +3. Run the app: + `npm run dev` \ No newline at end of file diff --git a/flutter_app/.gitignore b/flutter_app/.gitignore new file mode 100644 index 0000000..79c113f --- /dev/null +++ b/flutter_app/.gitignore @@ -0,0 +1,45 @@ +# 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 +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# 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/flutter_app/.metadata b/flutter_app/.metadata new file mode 100644 index 0000000..cca80bc --- /dev/null +++ b/flutter_app/.metadata @@ -0,0 +1,30 @@ +# 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: "8defaa71a77c16e8547abdbfad2053ce3a6e2d5b" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + - platform: ios + create_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + base_revision: 8defaa71a77c16e8547abdbfad2053ce3a6e2d5b + + # 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/flutter_app/README.md b/flutter_app/README.md new file mode 100644 index 0000000..66a1041 --- /dev/null +++ b/flutter_app/README.md @@ -0,0 +1,16 @@ +# pozo_app + +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/flutter_app/analysis_options.yaml b/flutter_app/analysis_options.yaml new file mode 100644 index 0000000..b941c4a --- /dev/null +++ b/flutter_app/analysis_options.yaml @@ -0,0 +1,34 @@ +# 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 + +analyzer: + errors: + deprecated_member_use: ignore + prefer_const_constructors: ignore + prefer_const_literals_to_create_immutables: ignore + +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/flutter_app/android/.gitignore b/flutter_app/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/flutter_app/android/.gitignore @@ -0,0 +1,14 @@ +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/flutter_app/android/app/build.gradle.kts b/flutter_app/android/app/build.gradle.kts new file mode 100644 index 0000000..982f8d3 --- /dev/null +++ b/flutter_app/android/app/build.gradle.kts @@ -0,0 +1,44 @@ +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") +} + +android { + namespace = "com.example.pozo_app" + compileSdk = flutter.compileSdkVersion + ndkVersion = "27.0.12077973" + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.pozo_app" + // 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/flutter_app/android/app/src/debug/AndroidManifest.xml b/flutter_app/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/flutter_app/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/flutter_app/android/app/src/main/AndroidManifest.xml b/flutter_app/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b22b4cc --- /dev/null +++ b/flutter_app/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/flutter_app/android/app/src/main/kotlin/com/example/pozo_app/MainActivity.kt b/flutter_app/android/app/src/main/kotlin/com/example/pozo_app/MainActivity.kt new file mode 100644 index 0000000..4b9c676 --- /dev/null +++ b/flutter_app/android/app/src/main/kotlin/com/example/pozo_app/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.pozo_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml b/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/flutter_app/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/flutter_app/android/app/src/main/res/drawable/launch_background.xml b/flutter_app/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/flutter_app/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/flutter_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/flutter_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/flutter_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/flutter_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/flutter_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/flutter_app/android/app/src/main/res/values-night/styles.xml b/flutter_app/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/flutter_app/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/flutter_app/android/app/src/main/res/values/styles.xml b/flutter_app/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/flutter_app/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/flutter_app/android/app/src/profile/AndroidManifest.xml b/flutter_app/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/flutter_app/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/flutter_app/android/build.gradle.kts b/flutter_app/android/build.gradle.kts new file mode 100644 index 0000000..89176ef --- /dev/null +++ b/flutter_app/android/build.gradle.kts @@ -0,0 +1,21 @@ +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/flutter_app/android/gradle.properties b/flutter_app/android/gradle.properties new file mode 100644 index 0000000..506086a --- /dev/null +++ b/flutter_app/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=false diff --git a/flutter_app/android/gradle/wrapper/gradle-wrapper.properties b/flutter_app/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ac3b479 --- /dev/null +++ b/flutter_app/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/flutter_app/android/settings.gradle.kts b/flutter_app/android/settings.gradle.kts new file mode 100644 index 0000000..ab39a10 --- /dev/null +++ b/flutter_app/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/flutter_app/ios/.gitignore b/flutter_app/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/flutter_app/ios/.gitignore @@ -0,0 +1,34 @@ +**/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/flutter_app/ios/Flutter/AppFrameworkInfo.plist b/flutter_app/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/flutter_app/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/flutter_app/ios/Flutter/Debug.xcconfig b/flutter_app/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/flutter_app/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/flutter_app/ios/Flutter/Release.xcconfig b/flutter_app/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/flutter_app/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/flutter_app/ios/Runner.xcodeproj/project.pbxproj b/flutter_app/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e605626 --- /dev/null +++ b/flutter_app/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,616 @@ +// !$*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 */; }; +/* 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 = ""; }; + 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 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 */, + ); + 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 = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + 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"; + }; + 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"; + }; +/* 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 = 12.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.pozoApp; + 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; + 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.pozoApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pozoApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pozoApp.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 = 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; + 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 = 12.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 = 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 = 12.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.pozoApp; + 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.pozoApp; + 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/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/flutter_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/flutter_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/flutter_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..e3773d4 --- /dev/null +++ b/flutter_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flutter_app/ios/Runner.xcworkspace/contents.xcworkspacedata b/flutter_app/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/flutter_app/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/flutter_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/flutter_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/flutter_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/flutter_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/flutter_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/flutter_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/flutter_app/ios/Runner/AppDelegate.swift b/flutter_app/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/flutter_app/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +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/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "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/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/flutter_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# 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/flutter_app/ios/Runner/Base.lproj/LaunchScreen.storyboard b/flutter_app/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/flutter_app/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flutter_app/ios/Runner/Base.lproj/Main.storyboard b/flutter_app/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/flutter_app/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flutter_app/ios/Runner/Info.plist b/flutter_app/ios/Runner/Info.plist new file mode 100644 index 0000000..8b56415 --- /dev/null +++ b/flutter_app/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Pozo App + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + pozo_app + 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/flutter_app/ios/Runner/Runner-Bridging-Header.h b/flutter_app/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/flutter_app/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/flutter_app/ios/RunnerTests/RunnerTests.swift b/flutter_app/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/flutter_app/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/flutter_app/lib/main.dart b/flutter_app/lib/main.dart new file mode 100644 index 0000000..96d9dae --- /dev/null +++ b/flutter_app/lib/main.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; +import 'theme.dart'; +import 'screens/welcome_screen.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + runApp(const PozoApp()); +} + +class PozoApp extends StatelessWidget { + const PozoApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'PozoApp', + theme: PozoTheme.lightTheme, + debugShowCheckedModeBanner: false, + home: const WelcomeScreen(), + ); + } +} diff --git a/flutter_app/lib/screens/billing_dashboard_screen.dart b/flutter_app/lib/screens/billing_dashboard_screen.dart new file mode 100644 index 0000000..3adaba9 --- /dev/null +++ b/flutter_app/lib/screens/billing_dashboard_screen.dart @@ -0,0 +1,1008 @@ +import 'dart:math'; +import 'package:flutter/material.dart'; + +class ProductItem { + final String id; + final String name; + final double price; + final int stock; + final String code; + + ProductItem({ + required this.id, + required this.name, + required this.price, + required this.stock, + required this.code, + }); +} + +class BillingItem { + final ProductItem product; + int quantity; + + BillingItem({ + required this.product, + required this.quantity, + }); +} + +class BillingDashboardScreen extends StatefulWidget { + final String businessName; + final String businessType; + final String gstin; + final bool barcodeScanner; + final bool kotManagement; + final bool inventoryAlerts; + + const BillingDashboardScreen({ + super.key, + required this.businessName, + required this.businessType, + required this.gstin, + required this.barcodeScanner, + required this.kotManagement, + required this.inventoryAlerts, + }); + + @override + State createState() => _BillingDashboardScreenState(); +} + +class _BillingDashboardScreenState extends State { + late List _products; + final List _billingList = []; + bool _printingInvoice = false; + String _invoiceNumber = 'POZO-26402'; + String _scanMessage = ''; + + final Map> _inventoryPresets = { + 'supermarket': [ + ProductItem(id: 'sm1', name: 'Premium Basmati Rice (1kg)', price: 120.0, stock: 45, code: '89012300052'), + ProductItem(id: 'sm2', name: 'Fresh Farm Milk (1L)', price: 65.0, stock: 2, code: '89045300010'), + ProductItem(id: 'sm3', name: 'Refined Cooking Oil (1L)', price: 165.0, stock: 18, code: '89010320491'), + ProductItem(id: 'sm4', name: 'Refined White Sugar (1kg)', price: 48.0, stock: 3, code: '89034200421'), + ProductItem(id: 'sm5', name: 'Organic Green T-Tea (250g)', price: 110.0, stock: 24, code: '89512300011'), + ProductItem(id: 'sm6', name: 'Whole Wheat Atta (5kg)', price: 230.0, stock: 7, code: '89011210042'), + ], + 'restaurant': [ + ProductItem(id: 'rt1', name: 'Fresh Paneer Butter Masala', price: 240.0, stock: 19, code: '9901230'), + ProductItem(id: 'rt2', name: 'Butter Tandoori Naan', price: 45.0, stock: 15, code: '9904530'), + ProductItem(id: 'rt3', name: 'Dum Veg Biryani Deluxe', price: 190.0, stock: 2, code: '9901032'), + ProductItem(id: 'rt4', name: 'Crispy Butter Masala Dosa', price: 90.0, stock: 22, code: '9903420'), + ProductItem(id: 'rt5', name: 'Rich Chocolate Milkshake', price: 120.0, stock: 3, code: '9951230'), + ProductItem(id: 'rt6', name: 'Hot Roasted Filter Coffee', price: 50.0, stock: 30, code: '9901121'), + ], + 'clothing': [ + ProductItem(id: 'cl1', name: 'Premium Oxford Cotton Shirt', price: 899.0, stock: 8, code: '77012301'), + ProductItem(id: 'cl2', name: 'Slim Fit Dark Jeans', price: 1599.0, stock: 2, code: '77045302'), + ProductItem(id: 'cl3', name: 'Designer Summer Slip Dress', price: 1299.0, stock: 5, code: '77010323'), + ProductItem(id: 'cl4', name: 'Graphic Printed Tee-Shirt', price: 450.0, stock: 40, code: '77034204'), + ProductItem(id: 'cl5', name: 'Breathable Sports Sneakers', price: 1899.0, stock: 3, code: '77512305'), + ProductItem(id: 'cl6', name: 'Stitch Leather Belt Brown', price: 349.0, stock: 12, code: '77011216'), + ], + 'kirana': [ + ProductItem(id: 'kr1', name: 'Premium Toor Dal (1kg)', price: 145.0, stock: 15, code: '4401230'), + ProductItem(id: 'kr2', name: 'Iodized Powdered Salt (1kg)', price: 22.0, stock: 50, code: '4404530'), + ProductItem(id: 'kr3', name: 'Herbal Moisturizer Soap', price: 42.0, stock: 2, code: '4401032'), + ProductItem(id: 'kr4', name: 'Anti-Germ Toothpaste (200g)', price: 85.0, stock: 16, code: '4403420'), + ProductItem(id: 'kr5', name: 'Dishwash Cleaning Soap', price: 25.0, stock: 3, code: '4451230'), + ProductItem(id: 'kr6', name: 'Red Chili Powder (200g)', price: 65.0, stock: 18, code: '4401121'), + ], + 'others': [ + ProductItem(id: 'ot1', name: 'Utility Household Scrubber', price: 35.0, stock: 33, code: '5501230'), + ProductItem(id: 'ot2', name: 'AAA Rechargeable Batteries', price: 120.0, stock: 4, code: '5504530'), + ProductItem(id: 'ot3', name: 'LED High Bright Focus Bulb', price: 140.0, stock: 2, code: '5501032'), + ProductItem(id: 'ot4', name: 'Water Bottle Stainless (1L)', price: 320.0, stock: 11, code: '5503420'), + ProductItem(id: 'ot5', name: 'Microfiber Floor Duster', price: 75.0, stock: 24, code: '5551230'), + ProductItem(id: 'ot6', name: 'Multi-plug Protection Adapter', price: 240.0, stock: 9, code: '5501121'), + ] + }; + + @override + void initState() { + super.initState(); + _products = _inventoryPresets[widget.businessType] ?? _inventoryPresets['supermarket']!; + } + + void _handleAddItem(ProductItem product) { + setState(() { + final index = _billingList.indexWhere((element) => element.product.id == product.id); + if (index != -1) { + final existingItem = _billingList[index]; + if (existingItem.quantity >= product.stock && widget.inventoryAlerts) { + _showErrorSnackBar('Cannot add more. Inventory limit reached for ${product.name}!'); + return; + } + existingItem.quantity += 1; + } else { + _billingList.add(BillingItem(product: product, quantity: 1)); + } + }); + } + + void _handleRemoveOne(String productId) { + setState(() { + final index = _billingList.indexWhere((element) => element.product.id == productId); + if (index != -1) { + if (_billingList[index].quantity > 1) { + _billingList[index].quantity -= 1; + } else { + _billingList.removeAt(index); + } + } + }); + } + + void _simulateBarcodeScan() { + if (!widget.barcodeScanner) return; + final random = Random(); + final randomProduct = _products[random.nextInt(_products.length)]; + _handleAddItem(randomProduct); + + setState(() { + _scanMessage = '🎯 Scanned EAN Barcode [${randomProduct.code}] - Added ${randomProduct.name}!'; + }); + + Future.delayed(const Duration(milliseconds: 3000), () { + if (mounted) { + setState(() { + _scanMessage = ''; + }); + } + }); + } + + void _clearRegister() { + setState(() { + _billingList.clear(); + }); + } + + void _showErrorSnackBar(String message) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message), + backgroundColor: Colors.red[800], + behavior: SnackBarBehavior.floating, + ), + ); + } + + double get _subtotal { + return _billingList.fold(0.0, (sum, item) => sum + (item.product.price * item.quantity)); + } + + bool get _hasGstin { + return widget.gstin.trim().isNotEmpty; + } + + double get _cgst => _hasGstin ? _subtotal * 0.09 : 0.0; + double get _sgst => _hasGstin ? _subtotal * 0.09 : 0.0; + double get _total => _subtotal + _cgst + _sgst; + + void _handleReviewAndGenerate() { + final random = Random(); + final invoiceVal = 'POZO-${random.nextInt(90000) + 10000}'; + setState(() { + _invoiceNumber = invoiceVal; + _printingInvoice = true; + }); + } + + void _closeReceiptAndReset() { + setState(() { + _printingInvoice = false; + _billingList.clear(); + }); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isDesktop = MediaQuery.of(context).size.width >= 600; + + return Stack( + children: [ + Scaffold( + backgroundColor: const Color(0xFF1E293B), // Slate-900 like + appBar: AppBar( + backgroundColor: const Color(0xFF0F172A), // Slate-950 like + elevation: 4, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () => Navigator.pop(context), + ), + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.businessName.isNotEmpty ? widget.businessName : 'Sharma General Store', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 15, + ), + ), + Row( + children: [ + Container( + width: 6, + height: 6, + decoration: const BoxDecoration( + color: Color(0xFF10B981), + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 4), + const Text( + 'Live Register', + style: TextStyle( + color: Colors.grey, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ], + ), + actions: [ + if (widget.barcodeScanner) + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Directionality( + textDirection: TextDirection.rtl, + child: ElevatedButton.icon( + onPressed: _simulateBarcodeScan, + style: ElevatedButton.styleFrom( + minimumSize: const Size(0, 32), + backgroundColor: theme.colorScheme.primary, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + icon: const Icon(Icons.qr_code_scanner, size: 16), + label: const Text( + 'Scan Item', + style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold), + ), + ), + ), + ), + if (widget.kotManagement) + Container( + margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 12), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.cyan.withOpacity(0.15), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.cyan.withOpacity(0.3)), + ), + child: const Center( + child: Text( + 'KOT', + style: TextStyle( + color: Colors.cyanAccent, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(width: 8), + ], + ), + body: SafeArea( + child: Column( + children: [ + // Scan Banner Message + if (_scanMessage.isNotEmpty) + Container( + width: double.infinity, + color: const Color(0xFF10B981), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.stars, color: Colors.white, size: 16), + const SizedBox(width: 8), + Expanded( + child: Text( + _scanMessage, + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + + // Main Layout Split + Expanded( + child: isDesktop + ? Row( + children: [ + Expanded(child: _buildCatalogPart(theme)), + _buildLedgerTrayPart(theme, isDesktop), + ], + ) + : Column( + children: [ + Expanded(child: _buildCatalogPart(theme)), + const Divider(color: Color(0xFF334155), height: 1), + SizedBox( + height: 240, + child: _buildLedgerTrayPart(theme, isDesktop), + ), + ], + ), + ), + + // Bottom Checkout sum action for Mobile ONLY + if (!isDesktop) _buildBottomComputationBar(theme), + ], + ), + ), + ), + + // Custom Overlay for Printable Invoice + if (_printingInvoice) _buildThermalReceiptOverlay(theme), + ], + ); + } + + Widget _buildCatalogPart(ThemeData theme) { + return Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'STORE CATALOG', + style: TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: 11, + letterSpacing: 1.0, + ), + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + decoration: BoxDecoration( + color: const Color(0xFF334155), + borderRadius: BorderRadius.circular(10), + ), + child: Text( + widget.businessType.toUpperCase(), + style: const TextStyle( + color: Colors.white70, + fontSize: 9, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 10), + Expanded( + child: GridView.builder( + physics: const BouncingScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + childAspectRatio: 1.4, + ), + itemCount: _products.length, + itemBuilder: (context, index) { + final prod = _products[index]; + final billingIndex = _billingList.indexWhere((element) => element.product.id == prod.id); + final countInCart = billingIndex != -1 ? _billingList[billingIndex].quantity : 0; + final remainingStock = prod.stock - countInCart; + final isLowStock = widget.inventoryAlerts && remainingStock <= 3; + final isOutOfStock = widget.inventoryAlerts && remainingStock <= 0; + + return InkWell( + onTap: isOutOfStock ? null : () => _handleAddItem(prod), + borderRadius: BorderRadius.circular(16), + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: countInCart > 0 + ? const Color(0xFF1E1B4B) // Deep indigo accent + : const Color(0xFF1E293B).withOpacity(0.8), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: countInCart > 0 ? theme.colorScheme.primary : const Color(0xFF334155), + width: countInCart > 0 ? 1.5 : 1.0, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + prod.name, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 11, + ), + ), + const SizedBox(height: 4), + Text( + '₹${prod.price.toStringAsFixed(0)}', + style: TextStyle( + color: theme.colorScheme.primary, + fontWeight: FontWeight.w800, + fontSize: 13, + ), + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (widget.inventoryAlerts) + Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: isLowStock + ? Colors.red.withOpacity(0.15) + : const Color(0xFF334155), + borderRadius: BorderRadius.circular(6), + ), + child: Text( + isOutOfStock ? 'Out of stock' : '$remainingStock Stock', + style: TextStyle( + color: isLowStock ? Colors.redAccent : Colors.grey, + fontSize: 8, + fontWeight: FontWeight.bold, + ), + ), + ) + else + const SizedBox(), + if (countInCart > 0) + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + '$countInCart', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 10, + ), + ), + ) + ], + ) + ], + ), + ), + ); + }, + ), + ) + ], + ), + ); + } + + Widget _buildLedgerTrayPart(ThemeData theme, bool isDesktop) { + return Container( + width: isDesktop ? 300 : double.infinity, + color: const Color(0xFF0F172A).withOpacity(0.3), + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'BILLING TRAY (${_billingList.length})', + style: const TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: 11, + letterSpacing: 1.0, + ), + ), + if (_billingList.isNotEmpty) + GestureDetector( + onTap: _clearRegister, + child: const Row( + children: [ + Icon(Icons.refresh, color: Colors.grey, size: 12), + SizedBox(width: 4), + Text( + 'Clear', + style: TextStyle( + color: Colors.grey, + fontWeight: FontWeight.bold, + fontSize: 10, + ), + ) + ], + ), + ) + ], + ), + const SizedBox(height: 10), + Expanded( + child: _billingList.isEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.shopping_cart_outlined, color: Colors.grey[600], size: 30), + const SizedBox(height: 8), + const Text( + 'No products selected.', + style: TextStyle(color: Colors.grey, fontSize: 11), + ), + const Text( + 'Tap items in catalog above.', + style: TextStyle(color: Colors.white30, fontSize: 10), + ), + ], + ), + ) + : ListView.builder( + physics: const BouncingScrollPhysics(), + itemCount: _billingList.length, + itemBuilder: (context, index) { + final item = _billingList[index]; + return Container( + margin: const EdgeInsets.only(bottom: 8), + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: const Color(0xFF1E293B), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFF334155), width: 0.5), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.product.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 11, + ), + ), + const SizedBox(height: 2), + Text( + '₹${item.product.price.toStringAsFixed(0)} × ${item.quantity}', + style: const TextStyle( + color: Colors.grey, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + Row( + children: [ + GestureDetector( + onTap: () => _handleRemoveOne(item.product.id), + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: const Color(0xFF334155), + borderRadius: BorderRadius.circular(6), + ), + child: const Icon(Icons.remove, size: 14, color: Colors.white), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + '${item.quantity}', + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ), + GestureDetector( + onTap: () => _handleAddItem(item.product), + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: const Color(0xFF334155), + borderRadius: BorderRadius.circular(6), + ), + child: const Icon(Icons.add, size: 14, color: Colors.white), + ), + ), + ], + ), + ], + ), + ); + }, + ), + ), + if (isDesktop) ...[ + const Divider(color: Color(0xFF334155), height: 16), + _buildComputationCalculations(theme), + const SizedBox(height: 10), + ElevatedButton( + onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate, + style: ElevatedButton.styleFrom( + backgroundColor: theme.colorScheme.primary, + disabledBackgroundColor: const Color(0xFF1E293B), + minimumSize: const Size.fromHeight(48), + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.receipt, size: 16), + SizedBox(width: 8), + Text('Generate Invoice'), + ], + ), + ) + ] + ], + ), + ); + } + + Widget _buildComputationCalculations(ThemeData theme) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Subtotal', style: TextStyle(color: Colors.grey, fontSize: 11)), + Text('₹${_subtotal.toStringAsFixed(2)}', style: const TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold)), + ], + ), + if (_hasGstin) ...[ + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('CGST (9%)', style: TextStyle(color: Colors.grey, fontSize: 11)), + Text('₹${_cgst.toStringAsFixed(2)}', style: const TextStyle(color: Colors.white70, fontSize: 11)), + ], + ), + const SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('SGST (9%)', style: TextStyle(color: Colors.grey, fontSize: 11)), + Text('₹${_sgst.toStringAsFixed(2)}', style: const TextStyle(color: Colors.white70, fontSize: 11)), + ], + ), + ], + const Padding( + padding: EdgeInsets.symmetric(vertical: 6.0), + child: Divider(color: Color(0xFF334155), height: 1), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Grand Total', style: TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold)), + Text( + '₹${_total.toStringAsFixed(2)}', + style: TextStyle( + color: theme.colorScheme.primary, + fontSize: 14, + fontWeight: FontWeight.w900, + ), + ), + ], + ), + ], + ); + } + + Widget _buildBottomComputationBar(ThemeData theme) { + return Container( + color: const Color(0xFF0F172A), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('GRAND TOTAL', style: TextStyle(color: Colors.grey, fontSize: 9, fontWeight: FontWeight.bold)), + Text( + '₹${_total.toStringAsFixed(2)}', + style: TextStyle( + color: theme.colorScheme.primary, + fontSize: 18, + fontWeight: FontWeight.w900, + ), + ) + ], + ), + ElevatedButton( + onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), + minimumSize: const Size(180, 44), + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.print, size: 16), + SizedBox(width: 8), + Text('Review & Invoice', style: TextStyle(fontSize: 12)), + ], + ), + ) + ], + ) + ], + ), + ); + } + + Widget _buildThermalReceiptOverlay(ThemeData theme) { + return Scaffold( + backgroundColor: Colors.black87, + body: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 30), + child: Container( + width: double.infinity, + constraints: const BoxConstraints(maxWidth: 340), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Thermal dotted-dash receipt border box + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey[400]!, width: 2, style: BorderStyle.solid), + borderRadius: BorderRadius.circular(4), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Column( + children: [ + Text( + widget.businessName.isNotEmpty ? widget.businessName.toUpperCase() : 'SHARMA GENERAL STORE', + textAlign: TextAlign.center, + style: const TextStyle( + color: Colors.black, + fontWeight: FontWeight.w900, + fontSize: 16, + fontFamily: 'monospace', + ), + ), + const SizedBox(height: 2), + Text( + '${widget.businessType.toUpperCase()} COUNTER', + style: const TextStyle( + color: Colors.grey, + fontSize: 9, + fontFamily: 'monospace', + ), + ), + if (_hasGstin) ...[ + const SizedBox(height: 4), + Text( + 'GSTIN: ${widget.gstin}', + style: const TextStyle( + color: Colors.black, + fontSize: 8, + fontWeight: FontWeight.bold, + fontFamily: 'monospace', + ), + ), + ] + ], + ), + ), + const SizedBox(height: 12), + const Divider(color: Colors.black38, thickness: 1), + const SizedBox(height: 4), + + // Metadata Info + _buildReceiptRow('Invoice No', _invoiceNumber), + _buildReceiptRow('Date Track', '${DateTime.now().day}/${DateTime.now().month}/${DateTime.now().year}'), + _buildReceiptRow('Terminal', 'Pozo Counter'), + const SizedBox(height: 4), + const Divider(color: Colors.black38, thickness: 1), + const SizedBox(height: 4), + + // Headers + const Row( + children: [ + Expanded( + flex: 6, + child: Text('Item Description', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 8, fontFamily: 'monospace')), + ), + Expanded( + flex: 2, + child: Text('Qty', textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 8, fontFamily: 'monospace')), + ), + Expanded( + flex: 4, + child: Text('Price', textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 8, fontFamily: 'monospace')), + ), + ], + ), + const SizedBox(height: 6), + + // Products + ..._billingList.map((item) => Padding( + padding: const EdgeInsets.only(bottom: 6.0), + child: Row( + children: [ + Expanded( + flex: 6, + child: Text( + item.product.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle(color: Colors.black87, fontSize: 9, fontFamily: 'monospace'), + ), + ), + Expanded( + flex: 2, + child: Text( + 'x${item.quantity}', + textAlign: TextAlign.right, + style: const TextStyle(color: Colors.black87, fontSize: 9, fontFamily: 'monospace'), + ), + ), + Expanded( + flex: 4, + child: Text( + '₹${(item.product.price * item.quantity).toStringAsFixed(0)}', + textAlign: TextAlign.right, + style: const TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 9, fontFamily: 'monospace'), + ), + ), + ], + ), + )), + + const Divider(color: Colors.black38, thickness: 1), + const SizedBox(height: 4), + + // Ledger math sum + _buildReceiptRow('Cart Total:', '₹${_subtotal.toStringAsFixed(2)}'), + if (_hasGstin) ...[ + _buildReceiptRow('CGST (9%):', '₹${_cgst.toStringAsFixed(2)}'), + _buildReceiptRow('SGST (9%):', '₹${_sgst.toStringAsFixed(2)}'), + ], + const SizedBox(height: 4), + _buildReceiptRow('NET TOTAL:', '₹${_total.toStringAsFixed(2)}', isBold: true), + + const SizedBox(height: 8), + const Divider(color: Colors.black38, thickness: 1), + const SizedBox(height: 8), + + const Center( + child: Column( + children: [ + Text( + 'THANK YOU FOR YOUR PATRONAGE!', + style: TextStyle(color: Colors.black54, fontSize: 8, fontWeight: FontWeight.bold, fontFamily: 'monospace'), + ), + SizedBox(height: 4), + Text( + 'Powered by PozoApp', + style: TextStyle(color: Colors.red, fontSize: 8, fontWeight: FontWeight.bold, fontFamily: 'monospace'), + ), + ], + ), + ), + ], + ), + ), + const SizedBox(height: 16), + ElevatedButton.icon( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('🧾 Thermal Printed: $_invoiceNumber successfully!'), + backgroundColor: const Color(0xFF10B981), + behavior: SnackBarBehavior.floating, + ), + ); + }, + icon: const Icon(Icons.print, size: 16), + label: const Text('Simulate Print Receipt', style: TextStyle(fontSize: 12)), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black, + foregroundColor: Colors.white, + minimumSize: const Size.fromHeight(42), + ), + ), + const SizedBox(height: 8), + ElevatedButton( + onPressed: _closeReceiptAndReset, + style: ElevatedButton.styleFrom( + backgroundColor: theme.colorScheme.primary, + minimumSize: const Size.fromHeight(42), + ), + child: const Text('New Ledger Sale', style: TextStyle(fontSize: 12)), + ), + ], + ), + ), + ), + ), + ); + } + + Widget _buildReceiptRow(String label, String val, {bool isBold = false}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: TextStyle( + fontSize: 9, + fontFamily: 'monospace', + fontWeight: isBold ? FontWeight.bold : FontWeight.normal, + color: isBold ? Colors.black : Colors.black87, + ), + ), + Text( + val, + style: TextStyle( + fontSize: 9, + fontFamily: 'monospace', + fontWeight: isBold ? FontWeight.bold : FontWeight.normal, + color: isBold ? Colors.black : Colors.black87, + ), + ), + ], + ), + ); + } +} diff --git a/flutter_app/lib/screens/business_setup_screen.dart b/flutter_app/lib/screens/business_setup_screen.dart new file mode 100644 index 0000000..62ec9ed --- /dev/null +++ b/flutter_app/lib/screens/business_setup_screen.dart @@ -0,0 +1,820 @@ +import 'package:flutter/material.dart'; +import 'dart:ui'; +import '../theme.dart'; +import 'customize_setup_screen.dart'; + +class BusinessSetupScreen extends StatefulWidget { + const BusinessSetupScreen({super.key}); + + @override + State createState() => _BusinessSetupScreenState(); +} + +class _BusinessSetupScreenState extends State { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _gstinController = TextEditingController(); + String _selectedCategory = 'supermarket'; + bool _isNameValid = false; + final Set _selectedDocs = {'GSTIN', 'FSSAI'}; + final Map _uploadedDocs = {}; + + @override + void initState() { + super.initState(); + _nameController.addListener(() { + setState(() { + _isNameValid = _nameController.text.trim().isNotEmpty; + }); + }); + } + + @override + void dispose() { + _nameController.dispose(); + _gstinController.dispose(); + super.dispose(); + } + + final List> _categories = [ + {'id': 'supermarket', 'name': 'Supermarket', 'icon': Icons.shopping_cart}, + {'id': 'restaurant', 'name': 'Restaurant', 'icon': Icons.restaurant}, + {'id': 'clothing', 'name': 'Clothing', 'icon': Icons.checkroom}, + {'id': 'kirana', 'name': 'Kirana', 'icon': Icons.local_mall}, + {'id': 'grocers', 'name': 'Grocers', 'icon': Icons.storefront}, + {'id': 'others', 'name': 'Others', 'icon': Icons.grid_view}, + ]; + + Widget _buildDocChip(String label, IconData icon) { + final theme = Theme.of(context); + final isSelected = _selectedDocs.contains(label); + return InkWell( + onTap: () { + setState(() { + if (isSelected) { + _selectedDocs.remove(label); + } else { + _selectedDocs.add(label); + } + }); + }, + borderRadius: BorderRadius.circular(8), + child: Container( + constraints: const BoxConstraints(minHeight: 48), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + color: isSelected ? const Color(0xFFFAF0F0) : Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: isSelected ? const Color(0xFFAF101A) : theme.colorScheme.outlineVariant, + width: isSelected ? 1.5 : 1, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + size: 16, + color: isSelected ? const Color(0xFFAF101A) : Colors.grey[600], + ), + const SizedBox(width: 8), + Text( + label, + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: isSelected ? const Color(0xFFAF101A) : Colors.grey[800], + ), + ), + ], + ), + ), + ); + } + + Widget _buildUploadSection(String docName, IconData icon) { + final theme = Theme.of(context); + final isUploaded = _uploadedDocs.containsKey(docName); + + return Container( + margin: const EdgeInsets.only(top: 12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outlineVariant, + width: 1, + ), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon(icon, color: const Color(0xFFAF101A), size: 18), + const SizedBox(width: 8), + Text( + '$docName Document', + style: theme.textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.onSurface, + ), + ), + ], + ), + IconButton( + icon: const Icon(Icons.close, size: 18, color: Colors.grey), + onPressed: () { + setState(() { + _selectedDocs.remove(docName); + }); + }, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ) + ], + ), + const SizedBox(height: 12), + if (isUploaded) ...[ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.grey[50], + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey[200]!), + ), + child: Row( + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: Colors.red[50], + borderRadius: BorderRadius.circular(8), + ), + child: const Center( + child: Icon( + Icons.insert_drive_file, + color: Color(0xFFAF101A), + size: 24, + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _uploadedDocs[docName] ?? 'Attached_document.pdf', + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(height: 2), + const Text( + 'Size: 1.2 MB • Ready', + style: TextStyle( + fontSize: 11, + color: Colors.grey, + ), + ), + ], + ), + ), + IconButton( + icon: const Icon(Icons.delete_outline, color: Colors.red), + onPressed: () { + setState(() { + _uploadedDocs.remove(docName); + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('$docName attachment removed.'), + behavior: SnackBarBehavior.floating, + ), + ); + }, + ), + ], + ), + ), + ] else ...[ + CustomPaint( + painter: DashedBorderPainter( + color: const Color(0xFFAF101A), + radius: 16, + ), + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 16), + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(16), + ), + child: Column( + children: [ + const Icon( + Icons.cloud_upload_outlined, + color: Color(0xFFAF101A), + size: 32, + ), + const SizedBox(height: 8), + Text( + 'Upload your $docName Proof', + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: Colors.grey, + ), + ), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton.icon( + onPressed: () { + setState(() { + _uploadedDocs[docName] = '${docName.toLowerCase().replaceAll(' ', '_')}_scan.jpg'; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('📸 Captured photo for $docName!'), + backgroundColor: const Color(0xFFAF101A), + behavior: SnackBarBehavior.floating, + ), + ); + }, + icon: const Icon(Icons.camera_alt, size: 14), + label: const Text('Take Photo'), + style: ElevatedButton.styleFrom( + minimumSize: const Size(0, 36), + backgroundColor: const Color(0xFFAF101A), + foregroundColor: Colors.white, + elevation: 1, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + const SizedBox(width: 8), + OutlinedButton.icon( + onPressed: () { + setState(() { + _uploadedDocs[docName] = 'gallery_${docName.toLowerCase().replaceAll(' ', '_')}.png'; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('📂 Uploaded $docName from gallery!'), + backgroundColor: Colors.green, + behavior: SnackBarBehavior.floating, + ), + ); + }, + icon: const Icon(Icons.photo_library, size: 14), + label: const Text('From Gallery'), + style: OutlinedButton.styleFrom( + foregroundColor: const Color(0xFFAF101A), + side: const BorderSide(color: Color(0xFFAF101A)), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ], + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final padding = context.responsivePadding; + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFFBA1A20)), + onPressed: () => Navigator.pop(context), + ), + title: Text( + 'PozoApp', + style: theme.textTheme.headlineMedium?.copyWith( + color: theme.colorScheme.primary, + fontWeight: FontWeight.bold, + ), + ), + actions: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: padding), + child: Center( + child: Text( + 'Step 3 of 5', + style: theme.textTheme.labelMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + bottom: PreferredSize( + preferredSize: const Size.fromHeight(6), + child: Row( + children: List.generate(5, (index) { + return Expanded( + child: Container( + height: 6, + margin: const EdgeInsets.symmetric(horizontal: 2.0), + decoration: BoxDecoration( + color: index <= 2 ? theme.colorScheme.primary : theme.colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(3), + ), + ), + ); + }), + ), + ), + ), + body: SafeArea( + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 600), + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Complete verification', + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 6), + Text( + 'Verify your business details to start selling.', + style: theme.textTheme.bodyMedium, + ), + const SizedBox(height: 16), + + // Name Field Input + Text( + 'Business/Shop Name *', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + TextField( + controller: _nameController, + decoration: const InputDecoration( + hintText: 'e.g. Sharma General Store', + ), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 16), + + // Category selection Block + Text( + 'Business Type *', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + + // Category custom grid (2x3) + GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + childAspectRatio: 2.2, + ), + itemCount: _categories.length, + itemBuilder: (context, index) { + final cat = _categories[index]; + final isSelected = _selectedCategory == cat['id']; + + return InkWell( + onTap: () { + setState(() { + _selectedCategory = cat['id']; + }); + }, + borderRadius: BorderRadius.circular(16), + child: Container( + decoration: BoxDecoration( + color: isSelected + ? const Color(0xFFAF101A).withOpacity(0.08) + : Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: isSelected ? const Color(0xFFAF101A) : const Color(0xFFE2E2E2), + width: isSelected ? 2 : 1, + ), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.01), + blurRadius: 4, + offset: const Offset(0, 2), + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Icon( + cat['icon'], + color: isSelected ? const Color(0xFFAF101A) : Colors.grey[600], + size: 26, + ), + ), + const SizedBox(height: 6), + Center( + child: Text( + cat['name'], + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: isSelected ? const Color(0xFFAF101A) : Colors.grey[800], + ), + ), + ) + ], + ), + ), + ); + }, + ), + const SizedBox(height: 16), + + // GSTIN optional Input group with Verify button on right-side + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'GSTIN', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + Text( + '(Optional)', + style: theme.textTheme.bodySmall?.copyWith( + color: Colors.grey[500], + ), + ) + ], + ), + const SizedBox(height: 8), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: TextField( + controller: _gstinController, + textCapitalization: TextCapitalization.characters, + decoration: const InputDecoration( + hintText: '15-DIGIT GST NUMBER', + ), + style: const TextStyle(fontWeight: FontWeight.bold, letterSpacing: 1.2), + ), + ), + const SizedBox(width: 12), + ElevatedButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('GSTIN Verified Successfully!'), + backgroundColor: Colors.green, + behavior: SnackBarBehavior.floating, + ), + ); + }, + style: ElevatedButton.styleFrom( + minimumSize: const Size(0, 48), + backgroundColor: theme.colorScheme.primary, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + ), + child: const Text('Verify'), + ), + ], + ), + const SizedBox(height: 6), + Text( + "Auto-fetches address & legal name on verification.", + style: TextStyle(fontSize: 11, color: Colors.grey[500]), + ), + const SizedBox(height: 16), + + // Shop Location Detect + Text( + 'Shop Location *', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + InkWell( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('📍 Location detected: Sector 62, Noida, UP'), + backgroundColor: Colors.green, + behavior: SnackBarBehavior.floating, + ), + ); + }, + borderRadius: BorderRadius.circular(16), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outlineVariant, + ), + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon( + Icons.my_location, + color: theme.colorScheme.primary, + size: 20, + ), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + 'Detect current location', + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + fontSize: 15, + ), + ), + const SizedBox(height: 2), + Text( + 'Pin shop address automatically', + style: TextStyle( + fontSize: 11, + color: Colors.grey[600], + ), + ), + ], + ), + ), + Icon( + Icons.chevron_right, + color: Colors.grey[400], + ), + ], + ), + ), + ), + const SizedBox(height: 16), + + // Identity/License Documents + Text( + 'Identity / License Documents (Select all that apply)', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + _buildDocChip('GSTIN', Icons.description), + _buildDocChip('FSSAI', Icons.restaurant), + _buildDocChip('Aadhar', Icons.badge_outlined), + _buildDocChip('Udhyog Aadhar', Icons.domain), + _buildDocChip('PAN', Icons.credit_card), + ], + ), + const SizedBox(height: 8), + // Expanded Upload Sections + ..._selectedDocs.map((doc) { + IconData docIcon = Icons.description; + if (doc == 'GSTIN') docIcon = Icons.description; + if (doc == 'FSSAI') docIcon = Icons.restaurant; + if (doc == 'Aadhar') docIcon = Icons.badge_outlined; + if (doc == 'Udhyog Aadhar') docIcon = Icons.domain; + if (doc == 'PAN') docIcon = Icons.credit_card; + return _buildUploadSection(doc, docIcon); + }), + const SizedBox(height: 16), + // Shop Facade Photo upload area + Text( + 'Shop Facade Photo *', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + InkWell( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('📸 Camera / Photo Upload Clicked!'), + behavior: SnackBarBehavior.floating, + ), + ); + }, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 24), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: theme.colorScheme.outlineVariant, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: theme.colorScheme.primary.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon( + Icons.add_a_photo_outlined, + color: theme.colorScheme.primary, + size: 24, + ), + ), + const SizedBox(height: 12), + Text( + 'Upload front view', + style: theme.textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.onSurface, + ), + ), + const SizedBox(height: 4), + Text( + 'Clear photo showing shop board', + style: TextStyle( + fontSize: 11, + color: Colors.grey[500], + ), + ), + ], + ), + ), + ), + const SizedBox(height: 12), + ], + ), + ), + ), + ), + + // Button docked + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: ElevatedButton( + onPressed: _isNameValid + ? () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => CustomizeSetupScreen( + businessName: _nameController.text.trim(), + businessType: _selectedCategory, + gstin: _gstinController.text.trim(), + ), + ), + ); + } + : null, + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(54), + backgroundColor: _isNameValid ? theme.colorScheme.primary : Colors.grey[200], + foregroundColor: _isNameValid ? Colors.white : Colors.grey[400], + elevation: _isNameValid ? 2 : 0, + ), + child: const Text('Continue to Verification'), + ), + ) + ], + ), + ), + ), + ), + ); + } +} + +class DashedBorderPainter extends CustomPainter { + final Color color; + final double strokeWidth; + final double gap; + final double radius; + + DashedBorderPainter({ + required this.color, + this.strokeWidth = 1.5, + this.gap = 4.0, + this.radius = 16.0, + }); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = color + ..strokeWidth = strokeWidth + ..style = PaintingStyle.stroke; + + final RRect rrect = RRect.fromRectAndRadius( + Rect.fromLTWH(0, 0, size.width, size.height), + Radius.circular(radius), + ); + + try { + final Path path = Path()..addRRect(rrect); + final Path dashPath = Path(); + + double distance = 0.0; + bool draw = true; + + for (final PathMetric metric in path.computeMetrics()) { + while (distance < metric.length) { + final double len = draw ? gap * 1.5 : gap; + if (draw) { + dashPath.addPath( + metric.extractPath(distance, (distance + len).clamp(0.0, metric.length)), + Offset.zero, + ); + } + distance += len; + draw = !draw; + } + } + + canvas.drawPath(dashPath, paint); + } catch (e) { + // Fallback for platform/renderers (such as Flutter Web HTML renderer) that do not support computeMetrics() + canvas.drawRRect(rrect, paint); + } + } + + @override + bool shouldRepaint(covariant DashedBorderPainter oldDelegate) { + return oldDelegate.color != color || + oldDelegate.strokeWidth != strokeWidth || + oldDelegate.gap != gap || + oldDelegate.radius != radius; + } +} diff --git a/flutter_app/lib/screens/customize_setup_screen.dart b/flutter_app/lib/screens/customize_setup_screen.dart new file mode 100644 index 0000000..d7dd5ce --- /dev/null +++ b/flutter_app/lib/screens/customize_setup_screen.dart @@ -0,0 +1,273 @@ +import 'package:flutter/material.dart'; +import '../theme.dart'; +import 'setup_complete_screen.dart'; + +class CustomizeSetupScreen extends StatefulWidget { + final String businessName; + final String businessType; + final String gstin; + + const CustomizeSetupScreen({ + super.key, + required this.businessName, + required this.businessType, + this.gstin = '', + }); + + @override + State createState() => _CustomizeSetupScreenState(); +} + +class _CustomizeSetupScreenState extends State { + bool _barcode = false; + bool _kot = false; + bool _inventory = true; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final padding = context.responsivePadding; + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFFBA1A20)), + onPressed: () => Navigator.pop(context), + ), + title: Row( + children: const [ + Icon(Icons.settings, color: Color(0xFFBA1A20), size: 18), + SizedBox(width: 6), + Text( + 'PozoApp', + style: TextStyle( + color: Color(0xFFBA1A20), + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SetupCompleteScreen( + businessName: widget.businessName, + businessType: widget.businessType, + gstin: widget.gstin, + barcodeScanner: false, + kotManagement: false, + inventoryAlerts: true, + ), + ), + ); + }, + child: Text( + 'Skip for Now', + style: TextStyle( + color: Colors.grey[750], + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ) + ], + bottom: PreferredSize( + preferredSize: const Size.fromHeight(6), + child: Row( + children: List.generate(5, (index) { + return Expanded( + child: Container( + height: 6, + margin: const EdgeInsets.symmetric(horizontal: 2.0), + decoration: BoxDecoration( + color: index <= 3 ? theme.colorScheme.primary : theme.colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(3), + ), + ), + ); + }), + ), + ), + ), + body: SafeArea( + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 600), + child: Column( + children: [ + Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10), + color: Colors.grey[50], + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + Text('Step 4 of 5', style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: Colors.grey)), + Text('Smart Setup', style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: Color(0xFFBA1A20))), + ], + ), + ), + Expanded( + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Customize Your Setup', + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + Text( + 'Turn on the features you need for your shop. You can always change these later in settings.', + style: theme.textTheme.bodyMedium, + ), + const SizedBox(height: 16), + + // Toggle 1: Barcode + _buildToggleCard( + Icons.qr_code_scanner, + 'Barcode Scanner', + 'Do you use a Barcode Scanner?', + _barcode, + (val) => setState(() => _barcode = val), + theme, + ), + const SizedBox(height: 12), + + // Toggle 2: KOT + _buildToggleCard( + Icons.receipt_long, + 'KOT Management', + 'Do you need Kitchen Order Ticket management?', + _kot, + (val) => setState(() => _kot = val), + theme, + ), + const SizedBox(height: 12), + + // Toggle 3: Inventory stock tracking + _buildToggleCard( + Icons.inventory_2, + 'Inventory Alerts', + 'Get notified when stock is running low.', + _inventory, + (val) => setState(() => _inventory = val), + theme, + ), + ], + ), + ), + ), + ), + + // Pinned action keys + Padding( + padding: EdgeInsets.all(padding), + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SetupCompleteScreen( + businessName: widget.businessName, + businessType: widget.businessType, + gstin: widget.gstin, + barcodeScanner: _barcode, + kotManagement: _kot, + inventoryAlerts: _inventory, + ), + ), + ); + }, + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(54), + ), + child: const Text('Save & Continue'), + ), + ) + ], + ), + ), + ), + ), + ); + } + + Widget _buildToggleCard( + IconData icon, + String title, + String subtitle, + bool value, + ValueChanged onChanged, + ThemeData theme, + ) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: Colors.grey[200]!), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.02), + blurRadius: 10, + offset: const Offset(0, 4), + ) + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: Colors.grey[100], + shape: BoxShape.circle, + ), + child: Icon(icon, color: Colors.grey[600], size: 22), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + const SizedBox(height: 4), + Text( + subtitle, + style: TextStyle( + fontSize: 11, + color: Colors.grey[500], + ), + ) + ], + ), + ), + Switch( + value: value, + onChanged: onChanged, + activeColor: Colors.white, + activeTrackColor: theme.colorScheme.primary, + ), + ], + ), + ); + } +} diff --git a/flutter_app/lib/screens/mobile_login_screen.dart b/flutter_app/lib/screens/mobile_login_screen.dart new file mode 100644 index 0000000..32cb606 --- /dev/null +++ b/flutter_app/lib/screens/mobile_login_screen.dart @@ -0,0 +1,474 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import '../theme.dart'; +import 'otp_verification_screen.dart'; + +class MobileLoginScreen extends StatefulWidget { + const MobileLoginScreen({super.key}); + + @override + State createState() => _MobileLoginScreenState(); +} + +class _MobileLoginScreenState extends State { + final TextEditingController _controller = TextEditingController(); + bool _isValid = false; + + @override + void initState() { + super.initState(); + _controller.addListener(_validateInput); + } + + void _validateInput() { + setState(() { + _isValid = _controller.text.length == 10; + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final gap = context.responsiveGap; + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFFAF101A)), + onPressed: () => Navigator.pop(context), + ), + title: Text( + 'PozoApp', + style: theme.textTheme.headlineMedium?.copyWith( + color: const Color(0xFFAF101A), + fontWeight: FontWeight.bold, + ), + ), + centerTitle: false, + elevation: 0, + backgroundColor: Colors.transparent, + ), + body: SafeArea( + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 600), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 16), + Expanded( + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 1. Progress Bar: Step 2 of 5 with "Mobile Login" label on right + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Step 2 of 5', + style: theme.textTheme.labelMedium?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const Text( + 'Mobile Login', + style: TextStyle( + fontFamily: 'Plus Jakarta Sans', + fontSize: 14, + fontWeight: FontWeight.bold, + color: Color(0xFFAF101A), + ), + ), + ], + ), + const SizedBox(height: 8), + Row( + children: List.generate(5, (index) { + return Expanded( + child: Container( + height: 6, + margin: EdgeInsets.only( + left: index == 0 ? 0 : 3.0, + right: index == 4 ? 0 : 3.0, + ), + decoration: BoxDecoration( + color: index <= 1 ? const Color(0xFFAF101A) : const Color(0xFFE2E2E2), + borderRadius: BorderRadius.circular(100), + ), + ), + ); + }), + ), + const SizedBox(height: 16), + + // Title Header & Secure Badge Group + Text( + 'Welcome Back', + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + Text( + 'Enter your mobile number to sign in or create a new account.', + style: theme.textTheme.bodyMedium, + ), + const SizedBox(height: 16), + + // 6. Top Badge: Green "Secure OTP Verification" chip with lock icon + Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: const Color(0xFFFAFFD1).withOpacity(0.8), + borderRadius: BorderRadius.circular(100), + border: Border.all(color: const Color(0xFF016619).withOpacity(0.3)), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.lock, size: 14, color: Color(0xFF016619)), + const SizedBox(width: 6), + Text( + 'Secure OTP Verification', + style: theme.textTheme.labelSmall?.copyWith( + color: const Color(0xFF016619), + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + const SizedBox(height: 16), + + // 2. Truecaller Card + Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF3F3F3), // light gray background (surface low) + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE4BEBA).withOpacity(0.5)), + ), + child: Column( + children: [ + Row( + children: [ + Container( + width: 40, + height: 40, + decoration: const BoxDecoration( + color: Color(0xFF005FAF), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.verified_user, // blue shield icon + color: Colors.white, + size: 24, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Verify instantly with', + style: theme.textTheme.bodySmall?.copyWith( + color: Colors.grey[600], + ), + ), + const Text( + 'Truecaller', + style: TextStyle( + fontFamily: 'Plus Jakarta Sans', + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 20), + const Text( + '+91 98765 43210', + style: TextStyle( + fontFamily: 'Plus Jakarta Sans', + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + const SizedBox(height: 16), + ElevatedButton.icon( + onPressed: () { + _controller.text = '9876543210'; + setState(() { + _isValid = true; + }); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('⚡ Phone verified automatically with Truecaller! Joining PozoApp...'), + backgroundColor: Color(0xFF005FAF), + behavior: SnackBarBehavior.floating, + ), + ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const OtpVerificationScreen( + mobileNumber: '9876543210', + ), + ), + ); + }, + icon: const Icon(Icons.flash_on, size: 18, color: Colors.white), + label: const Text( + '1-Tap Verification', + style: TextStyle( + fontFamily: 'Inter', + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF005FAF), + foregroundColor: Colors.white, + minimumSize: const Size.fromHeight(56), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), // 8px for buttons + ), + elevation: 1, + ), + ), + const SizedBox(height: 12), + Text( + 'No OTP required. Your phone will be verified automatically.', + textAlign: TextAlign.center, + style: theme.textTheme.bodySmall?.copyWith( + color: Colors.grey[600], + height: 1.4, + ), + ), + ], + ), + ), + + SizedBox(height: gap), + + // 3. Divider: "Or enter mobile number manually" + Row( + children: [ + const Expanded(child: Divider(color: Color(0xFFE4BEBA))), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + 'Or enter mobile number manually', + style: theme.textTheme.labelMedium?.copyWith( + color: Colors.grey[600], + fontWeight: FontWeight.w500, + fontSize: 12, + ), + ), + ), + const Expanded(child: Divider(color: Color(0xFFE4BEBA))), + ], + ), + + SizedBox(height: gap), + + Text( + 'Mobile Number', + style: theme.textTheme.labelSmall?.copyWith( + color: theme.colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + + // 4. Mobile Number field: Country code group on left, number field on right + Container( + height: 56, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: theme.colorScheme.outlineVariant), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.02), + blurRadius: 4, + offset: const Offset(0, 2), + ) + ], + ), + child: Row( + children: [ + // Flag and code prefix box + Container( + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + border: Border( + right: BorderSide(color: theme.colorScheme.outlineVariant), + ), + ), + child: Row( + children: [ + // Indian flag representation + Container( + width: 22, + height: 14, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey[300]!, width: 0.5), + ), + child: Column( + children: [ + Container(height: 4, color: const Color(0xFFFF9933)), + Container( + height: 4, + color: Colors.white, + child: Center( + child: Container( + width: 2, + height: 2, + decoration: const BoxDecoration( + color: Color(0xFF000080), + shape: BoxShape.circle, + ), + ), + ), + ), + Container(height: 4, color: const Color(0xFF128807)), + ], + ), + ), + const SizedBox(width: 8), + Text( + '+91', + style: theme.textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.onSurface, + ), + ) + ], + ), + ), + + // Input field + Expanded( + child: TextField( + controller: _controller, + keyboardType: TextInputType.phone, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + LengthLimitingTextInputFormatter(10), + ], + decoration: const InputDecoration( + hintText: '00000 00000', + border: InputBorder.none, + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + filled: false, + contentPadding: EdgeInsets.symmetric(horizontal: 16), + ), + style: theme.textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.onSurface, + ), + ), + ) + ], + ), + ), + SizedBox(height: gap * 2), + ], + ), + ), + ), + + // 5. Bottom buttons + Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Full width red "Send OTP" button + ElevatedButton( + onPressed: _isValid + ? () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => OtpVerificationScreen( + mobileNumber: _controller.text, + ), + ), + ); + } + : null, + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(56), + backgroundColor: _isValid ? const Color(0xFFAF101A) : Colors.grey[200], + foregroundColor: _isValid ? Colors.white : Colors.grey[400], + elevation: _isValid ? 2 : 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), // 8px default button radius + ), + ), + child: const Text('Send OTP'), + ), + SizedBox(height: gap / 2), + // Outline style red "Help / Talk to Support" button with chat icon + OutlinedButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('💬 Connecting with Pozo Support... Please wait.'), + behavior: SnackBarBehavior.floating, + ), + ); + }, + style: OutlinedButton.styleFrom( + minimumSize: const Size.fromHeight(56), + side: const BorderSide(color: Color(0xFFAF101A), width: 2), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), // 8px default button radius + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.forum, color: Color(0xFFAF101A), size: 18), + const SizedBox(width: 8), + const Text( + 'Help / Talk to Support', + style: TextStyle( + color: Color(0xFFAF101A), + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/flutter_app/lib/screens/otp_verification_screen.dart b/flutter_app/lib/screens/otp_verification_screen.dart new file mode 100644 index 0000000..a612a49 --- /dev/null +++ b/flutter_app/lib/screens/otp_verification_screen.dart @@ -0,0 +1,382 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import '../theme.dart'; +import 'business_setup_screen.dart'; + +class OtpVerificationScreen extends StatefulWidget { + final String mobileNumber; + + const OtpVerificationScreen({super.key, required this.mobileNumber}); + + @override + State createState() => _OtpVerificationScreenState(); +} + +class _OtpVerificationScreenState extends State { + late Timer _timer; + int _timeLeft = 45; + final List _controllers = List.generate(6, (_) => TextEditingController()); + final List _focusNodes = List.generate(6, (_) => FocusNode()); + + @override + void initState() { + super.initState(); + _startCountdown(); + } + + void _startCountdown() { + _timeLeft = 45; + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (_timeLeft <= 0) { + _timer.cancel(); + } else { + setState(() { + _timeLeft--; + }); + } + }); + } + + @override + void dispose() { + _timer.cancel(); + for (var controller in _controllers) { + controller.dispose(); + } + for (var node in _focusNodes) { + node.dispose(); + } + super.dispose(); + } + + String _getFormattedTime() { + return '00:${_timeLeft.toString().padLeft(2, '0')}'; + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final padding = context.responsivePadding; + + final displayMobile = widget.mobileNumber.length == 10 + ? '+91 ${widget.mobileNumber.substring(0, 5)} ${widget.mobileNumber.substring(5)}' + : '+91 ${widget.mobileNumber}'; + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Color(0xFFBA1A20)), + onPressed: () => Navigator.pop(context), + ), + title: Text( + 'PozoApp', + style: theme.textTheme.headlineMedium?.copyWith( + color: theme.colorScheme.primary, + fontWeight: FontWeight.bold, + ), + ), + actions: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: padding), + child: Center( + child: Text( + 'Step 2.5 of 5', + style: theme.textTheme.labelMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + bottom: PreferredSize( + preferredSize: const Size.fromHeight(6), + child: Row( + children: List.generate(5, (index) { + return Expanded( + child: Container( + height: 6, + margin: const EdgeInsets.symmetric(horizontal: 2.0), + decoration: BoxDecoration( + color: index <= 1 + ? theme.colorScheme.primary + : (index == 2 ? theme.colorScheme.primary.withOpacity(0.5) : theme.colorScheme.surfaceContainerHighest), + borderRadius: BorderRadius.circular(3), + ), + ), + ); + }), + ), + ), + ), + body: SafeArea( + child: Column( + children: [ + Expanded( + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 600), + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Alert envelope pulse symbol + Center( + child: Container( + width: 96, + height: 96, + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerHigh, + shape: BoxShape.circle, + ), + child: Center( + child: Container( + width: 72, + height: 72, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.06), + blurRadius: 10, + ) + ], + ), + child: Icon( + Icons.sms, + color: theme.colorScheme.primary, + size: 38, + ), + ), + ), + ), + ), + const SizedBox(height: 16), + Text( + 'Verifying your number', + textAlign: TextAlign.center, + style: theme.textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + "Sent code to $displayMobile", + style: theme.textTheme.bodyMedium, + ), + const SizedBox(width: 8), + GestureDetector( + onTap: () => Navigator.pop(context), + child: Text( + 'Edit', + style: TextStyle( + color: theme.colorScheme.primary, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ), + ], + ), + + const SizedBox(height: 16), + + // 6 Custom Inputs Fields + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(11, (index) { + if (index.isOdd) { + return const SizedBox(width: 8); + } + final fieldIndex = index ~/ 2; + return SizedBox( + width: 44, + child: TextField( + controller: _controllers[fieldIndex], + focusNode: _focusNodes[fieldIndex], + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + maxLength: 1, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + decoration: InputDecoration( + counterText: '', + contentPadding: const EdgeInsets.symmetric(vertical: 12), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: theme.colorScheme.outlineVariant), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: theme.colorScheme.primary, width: 2), + ), + ), + onChanged: (value) { + if (value.isNotEmpty && fieldIndex < 5) { + _focusNodes[fieldIndex + 1].requestFocus(); + } + }, + ), + ); + }), + ), + + const SizedBox(height: 16), + + // Auto detect loader + Container( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerLow, + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: 14, + height: 14, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(theme.colorScheme.primary), + ), + ), + const SizedBox(width: 12), + Text( + 'Auto-detecting OTP...', + style: theme.textTheme.bodySmall?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + const SizedBox(height: 16), + + // Resending timer action column + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.schedule, size: 16, color: Colors.grey), + const SizedBox(width: 6), + Text( + _timeLeft > 0 + ? 'Resend code in ${_getFormattedTime()}' + : 'Resend Code via SMS', + style: theme.textTheme.bodyMedium, + ), + ], + ), + const SizedBox(height: 16), + + // WhatsApp custom CTA button + ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black87, + side: const BorderSide(color: Color(0xFFE2E2E2)), + elevation: 1, + minimumSize: const Size(200, 48), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: const [ + Text( + 'Resend via WhatsApp', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ) + ], + ), + ), + ), + ), + ), + ), + + // Pinned Bottom Dock + Container( + height: 80, + decoration: BoxDecoration( + color: Colors.white, + border: Border(top: BorderSide(color: Colors.grey[200]!)), + ), + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 600), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildFooterAction(Icons.help_outline, 'Help'), + _buildFooterAction(Icons.save, 'Save Draft'), + TextButton.icon( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const BusinessSetupScreen(), + ), + ); + }, + icon: const Text( + 'Verify Manually', + style: TextStyle(fontWeight: FontWeight.bold), + ), + label: const Icon(Icons.arrow_forward, size: 16), + style: TextButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: theme.colorScheme.primary, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ) + ], + ), + ), + ), + ), + ) + ], + ), + ), + ); + } + + Widget _buildFooterAction(IconData icon, String label) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(icon, color: Colors.grey[600], size: 22), + const SizedBox(height: 4), + Text( + label, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.grey[600], + ), + ) + ], + ); + } +} diff --git a/flutter_app/lib/screens/setup_complete_screen.dart b/flutter_app/lib/screens/setup_complete_screen.dart new file mode 100644 index 0000000..e569dcb --- /dev/null +++ b/flutter_app/lib/screens/setup_complete_screen.dart @@ -0,0 +1,342 @@ +import 'package:flutter/material.dart'; +import '../theme.dart'; +import 'billing_dashboard_screen.dart'; + +class SetupCompleteScreen extends StatelessWidget { + final String businessName; + final String businessType; + final String gstin; + final bool barcodeScanner; + final bool kotManagement; + final bool inventoryAlerts; + + const SetupCompleteScreen({ + super.key, + required this.businessName, + required this.businessType, + this.gstin = '', + this.barcodeScanner = false, + this.kotManagement = false, + this.inventoryAlerts = true, + }); + + String _getCategoryDisplayName(String id) { + final cleanId = id.replaceAll('category/', '').trim().toLowerCase(); + switch (cleanId) { + case 'supermarket': + return 'Supermarket'; + case 'restaurant': + return 'Restaurant'; + case 'clothing': + return 'Clothing / Boutique'; + case 'kirana': + return 'Retail / Grocery (Kirana)'; + case 'others': + default: + return 'Retail / Others'; + } + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final categoryText = _getCategoryDisplayName(businessType); + final gap = context.responsiveGap; + + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + title: Row( + children: const [ + Icon(Icons.check_circle, color: Colors.green, size: 18), + SizedBox(width: 6), + Text( + 'Step 5 of 5 Completed', + style: TextStyle( + color: Colors.green, + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], + ), + bottom: PreferredSize( + preferredSize: const Size.fromHeight(6), + child: Container( + height: 6, + color: theme.colorScheme.primary, + ), + ), + ), + body: SafeArea( + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 600), + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 24), + + // Circular Green Check badge + Container( + width: 96, + height: 96, + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 16, + offset: Offset(0, 8), + ) + ], + ), + child: Center( + child: Container( + width: 72, + height: 72, + decoration: const BoxDecoration( + color: Colors.green, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check, + color: Colors.white, + size: 40, + ), + ), + ), + ), + + SizedBox(height: gap), + Text( + 'Setup Complete! 🎉', + textAlign: TextAlign.center, + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + Text( + 'Your billing dashboard is ready for action.', + textAlign: TextAlign.center, + style: theme.textTheme.bodyMedium, + ), + + SizedBox(height: gap * 1.5), + + // Glassmorphism summary Card + Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + border: Border.all(color: Colors.grey[200]!), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 20, + offset: const Offset(0, 8), + ) + ], + ), + child: Column( + children: [ + // Row 1: Store name + Row( + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: Colors.grey[100], + shape: BoxShape.circle, + ), + child: const Icon(Icons.storefront, color: Colors.black87), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'BUSINESS NAME', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.grey, + letterSpacing: 1.0, + ), + ), + const SizedBox(height: 4), + Text( + businessName, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ], + ), + ) + ], + ), + + // Divider line + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Divider(color: Colors.grey[200]), + ), + + // Row 2: Category type + Row( + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: Colors.grey[100], + shape: BoxShape.circle, + ), + child: const Icon(Icons.category, color: Colors.black87), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'BUSINESS TYPE', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.grey, + letterSpacing: 1.0, + ), + ), + const SizedBox(height: 4), + Text( + categoryText, + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ], + ), + ) + ], + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: Divider(color: Colors.grey[200]), + ), + Row( + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: Colors.grey[100], + shape: BoxShape.circle, + ), + child: const Icon(Icons.settings, color: Colors.black87), + ), + const SizedBox(width: 14), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'ACTIVE CONFIGURATIONS', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.grey, + letterSpacing: 1.0, + ), + ), + const SizedBox(height: 4), + Text( + [ + if (barcodeScanner) 'Barcode Enabled', + if (kotManagement) 'KOT/Kitchen Order', + if (inventoryAlerts) 'Low Stock Warnings', + if (!barcodeScanner && !kotManagement && !inventoryAlerts) 'Standard Register', + ].join(', '), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + ], + ), + ) + ], + ) + ], + ), + ), + + const SizedBox(height: 24), + + // Primary Launcher CTA + ElevatedButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('⚡ Launching Register Dashboard... Enjoy billing!'), + behavior: SnackBarBehavior.floating, + backgroundColor: Colors.green, + duration: Duration(milliseconds: 1500), + ), + ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => BillingDashboardScreen( + businessName: businessName, + businessType: businessType, + gstin: gstin, + barcodeScanner: barcodeScanner, + kotManagement: kotManagement, + inventoryAlerts: inventoryAlerts, + ), + ), + ); + }, + style: ElevatedButton.styleFrom( + minimumSize: const Size.fromHeight(56), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Icon(Icons.receipt, size: 20), + SizedBox(width: 8), + Text('Create Your First Bill'), + ], + ), + ), + const SizedBox(height: 24), + ], + ), + ), + ), + ), + ), + ), + ); +} +} diff --git a/flutter_app/lib/screens/welcome_screen.dart b/flutter_app/lib/screens/welcome_screen.dart new file mode 100644 index 0000000..217b757 --- /dev/null +++ b/flutter_app/lib/screens/welcome_screen.dart @@ -0,0 +1,494 @@ +import 'package:flutter/material.dart'; +import '../theme.dart'; +import 'mobile_login_screen.dart'; + +class WelcomeScreen extends StatelessWidget { + const WelcomeScreen({super.key}); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isMobile = context.isMobile; + + return Scaffold( + body: SafeArea( + child: Column( + children: [ + // Top Progress bar indicator - 1st segment active + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: Row( + children: List.generate(5, (index) { + return Expanded( + child: Container( + height: 4, + margin: const EdgeInsets.symmetric(horizontal: 2.0), + decoration: BoxDecoration( + color: index == 0 ? theme.colorScheme.primary : theme.colorScheme.surfaceContainerHighest, + borderRadius: BorderRadius.circular(2), + ), + ), + ); + }), + ), + ), + + // Scrollable / Responsive Content + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + final maxWidth = constraints.maxWidth; + if (maxWidth >= 768) { + // Desktop / Tablet Double-Column Layout + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 1000), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Left column: content + button + Expanded( + flex: 5, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildLogo(theme), + const SizedBox(height: 16), + Text( + 'Manage your business billing in 3 clicks!', + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + Text( + 'The fastest, most reliable tool for Indian MSMEs to run their shop.', + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: 16), + _buildSeal(theme), + const SizedBox(height: 16), + _buildCTAColumn(context, theme), + ], + ), + ), + const SizedBox(width: 32), + // Right column: mock card + Expanded( + flex: 4, + child: Center( + child: _buildMockDashboard(theme), + ), + ), + ], + ), + ), + ), + ), + ); + } else { + // Mobile Single Column Layout + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 16), + _buildLogo(theme), + const SizedBox(height: 16), + Text( + 'Manage your business billing in 3 clicks!', + textAlign: TextAlign.left, + style: theme.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + Text( + 'The fastest, most reliable tool for Indian MSMEs to run their shop.', + textAlign: TextAlign.left, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: 16), + _buildSeal(theme), + const SizedBox(height: 24), + Center(child: _buildMockDashboard(theme)), + const SizedBox(height: 24), + ], + ), + ), + ); + } + }, + ), + ), + + // Pinned Bottom Button on Mobile + if (isMobile) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), + child: _buildCTAColumn(context, theme), + ), + ], + ), + ), + ); + } + + Widget _buildLogo(ThemeData theme) { + return Container( + width: 80, + height: 80, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: theme.colorScheme.primary.withOpacity(0.15), + blurRadius: 24, + offset: const Offset(0, 8), + ) + ], + ), + alignment: Alignment.center, + child: Stack( + clipBehavior: Clip.none, + children: [ + Text( + 'Pozo', + style: theme.textTheme.headlineMedium?.copyWith( + color: Colors.white, + fontWeight: FontWeight.w800, + letterSpacing: -1.0, + ), + ), + Positioned( + top: -16, + right: -16, + child: Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.amber[700], + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2), + ), + child: const Text( + 'IN', + style: TextStyle( + color: Colors.white, + fontSize: 8, + fontWeight: FontWeight.bold, + ), + ), + ), + ) + ], + ), + ); + } + + Widget _buildSeal(ThemeData theme) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceContainerLow, + borderRadius: BorderRadius.circular(20), + border: Border.all(color: theme.colorScheme.outlineVariant), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.verified, + size: 16, + color: theme.colorScheme.tertiary, + ), + const SizedBox(width: 6), + Text( + 'Trusted by 10,000+ merchants', + style: theme.textTheme.bodySmall?.copyWith( + fontWeight: FontWeight.w600, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ); + } + + Widget _buildMockDashboard(ThemeData theme) { + return Container( + width: 280, + height: 230, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(24), + border: Border.all(color: theme.colorScheme.outlineVariant), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.04), + blurRadius: 20, + offset: const Offset(0, 8), + ) + ], + ), + child: Stack( + clipBehavior: Clip.none, + children: [ + Column( + children: [ + Container( + height: 44, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: Colors.grey[50], + borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), + border: Border(bottom: BorderSide(color: Colors.grey[200]!)), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 8), + Container( + width: 70, + height: 8, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(4), + ), + ), + ], + ), + Container( + width: 14, + height: 14, + decoration: BoxDecoration( + color: Colors.grey[300], + shape: BoxShape.circle, + ), + ) + ], + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _buildMockRow(Icons.description, Colors.red[50]!, Colors.red), + const SizedBox(height: 14), + _buildMockRow(Icons.poll, Colors.green[50]!, Colors.green), + ], + ), + ), + ) + ], + ), + Positioned( + top: 60, + right: -12, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(14), + border: Border.all(color: Colors.grey[200]!), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.06), + blurRadius: 10, + offset: const Offset(0, 4), + ) + ], + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(2), + decoration: const BoxDecoration( + color: Colors.green, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check, + color: Colors.white, + size: 10, + ), + ), + const SizedBox(width: 6), + const Text( + 'Saved', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 11, + color: Colors.black, + ), + ) + ], + ), + ), + ), + Positioned( + bottom: 30, + left: -16, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: theme.colorScheme.primary.withOpacity(0.2), + blurRadius: 12, + offset: const Offset(0, 6), + ) + ], + ), + child: const Text( + '₹ 4,500', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ), + ) + ], + ), + ); + } + + Widget _buildCTAColumn(BuildContext context, ThemeData theme) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: context.isMobile ? CrossAxisAlignment.center : CrossAxisAlignment.start, + children: [ + ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => const MobileLoginScreen()), + ); + }, + style: ElevatedButton.styleFrom( + minimumSize: const Size(260, 54), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: const [ + Text('Get Started'), + SizedBox(width: 8), + Icon(Icons.arrow_forward, size: 18), + ], + ), + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: context.isMobile ? MainAxisAlignment.center : MainAxisAlignment.start, + children: [ + Container( + width: 10, + height: 10, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 6), + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: Colors.grey[300], + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 6), + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: Colors.grey[300], + shape: BoxShape.circle, + ), + ), + ], + ) + ], + ); + } + + Widget _buildMockRow(IconData icon, Color bg, Color color) { + return Container( + height: 48, + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: bg.withOpacity(0.4), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey[100]!), + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(6), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Icon(icon, color: color, size: 16), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 100, + height: 6, + decoration: BoxDecoration( + color: Colors.grey[400], + borderRadius: BorderRadius.circular(3), + ), + ), + const SizedBox(height: 6), + Container( + width: 50, + height: 4, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(2), + ), + ), + ], + ), + ), + Icon(Icons.more_vert, color: Colors.grey[400], size: 16) + ], + ), + ); + } +} diff --git a/flutter_app/lib/theme.dart b/flutter_app/lib/theme.dart new file mode 100644 index 0000000..7ef660b --- /dev/null +++ b/flutter_app/lib/theme.dart @@ -0,0 +1,175 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class PozoTheme { + // Brand color palette definitions + static const Color primary = Color(0xFFBA1A20); + static const Color primaryContainer = Color(0xFFD32F2F); + static const Color onPrimary = Color(0xFFFFFFFF); + + static const Color background = Color(0xFFF9F9F9); + static const Color surface = Color(0xFFF9F9F9); + static const Color surfaceContainerLowest = Color(0xFFFFFFFF); + static const Color surfaceContainerLow = Color(0xFFF3F3F3); + static const Color surfaceContainerHigh = Color(0xFFE8E8E8); + + static const Color onSurface = Color(0xFF1A1C1C); + static const Color onSurfaceVariant = Color(0xFF5B403D); + static const Color outline = Color(0xFF8F6F6C); + static const Color outlineVariant = Color(0xFFE4BEBA); + + static const Color tertiary = Color(0xFF016619); + static const Color tertiaryFixed = Color(0xFF9DF898); + static const Color error = Color(0xFFBA1A1A); + + static ThemeData get lightTheme { + return ThemeData( + useMaterial3: true, + colorScheme: const ColorScheme.light( + primary: primary, + primaryContainer: primaryContainer, + onPrimary: onPrimary, + surface: surface, + onSurface: onSurface, + onSurfaceVariant: onSurfaceVariant, + outline: outline, + outlineVariant: outlineVariant, + tertiary: tertiary, + error: error, + ), + scaffoldBackgroundColor: background, + textTheme: TextTheme( + // Plus Jakarta Sans headings + displayLarge: GoogleFonts.plusJakartaSans( + fontSize: 30, + fontWeight: FontWeight.bold, + height: 1.25, + color: onSurface, + ), + headlineLarge: GoogleFonts.plusJakartaSans( + fontSize: 24, + fontWeight: FontWeight.bold, + height: 1.33, + color: onSurface, + ), + headlineMedium: GoogleFonts.plusJakartaSans( + fontSize: 22, + fontWeight: FontWeight.w600, + height: 1.27, + color: onSurface, + ), + // Inter helper body fonts + bodyLarge: GoogleFonts.inter( + fontSize: 18, + fontWeight: FontWeight.normal, + height: 1.44, + color: onSurfaceVariant, + ), + bodyMedium: GoogleFonts.inter( + fontSize: 16, + fontWeight: FontWeight.normal, + height: 1.5, + color: onSurfaceVariant, + ), + labelLarge: GoogleFonts.inter( + fontSize: 20, + fontWeight: FontWeight.w600, + height: 1.2, + letterSpacing: 0.5, + ), + labelMedium: GoogleFonts.inter( + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.4, + letterSpacing: 1.0, + ), + labelSmall: GoogleFonts.inter( + fontSize: 11, + fontWeight: FontWeight.bold, + letterSpacing: 1.0, + ), + ), + + // Inputs decorating styles + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: surfaceContainerLowest, + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: outlineVariant), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: outlineVariant), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: primary, width: 1.5), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(16), + borderSide: const BorderSide(color: error), + ), + hintStyle: GoogleFonts.inter(color: outlineVariant, fontSize: 16), + ), + + // Button themes helper + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: primary, + foregroundColor: onPrimary, + minimumSize: const Size.fromHeight(54), + elevation: 2, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + textStyle: GoogleFonts.plusJakartaSans( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} + +extension ResponsiveLayout on BuildContext { + double get responsivePadding { + final width = MediaQuery.of(this).size.width; + if (width < 600) { + return 16.0; + } else if (width < 1024) { + return 24.0; + } else { + return 32.0; + } + } + + double get responsiveMargin { + final width = MediaQuery.of(this).size.width; + if (width < 600) { + return 12.0; + } else if (width < 1024) { + return 20.0; + } else { + return 28.0; + } + } + + double get responsiveGap { + final width = MediaQuery.of(this).size.width; + if (width < 600) { + return 16.0; + } else if (width < 1024) { + return 24.0; + } else { + return 32.0; + } + } + + bool get isMobile => MediaQuery.of(this).size.width < 600; + bool get isTablet => MediaQuery.of(this).size.width >= 600 && MediaQuery.of(this).size.width < 1024; + bool get isWeb => MediaQuery.of(this).size.width >= 1024; +} + diff --git a/flutter_app/pubspec.lock b/flutter_app/pubspec.lock new file mode 100644 index 0000000..0bd94e9 --- /dev/null +++ b/flutter_app/pubspec.lock @@ -0,0 +1,341 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + 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" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: 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: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: e20ff62b158b96f392bfc8afe29dee1503c94fbea2cbe8186fd59b756b8ae982 + url: "https://pub.dev" + source: hosted + version: "5.1.0" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + 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: "3b4c1fc3aa55ddc9cd4aa6759984330d5c8e66aa7702a6223c61540dc6380c37" + url: "https://pub.dev" + source: hosted + version: "2.2.19" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + 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" + 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" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" +sdks: + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.29.0" diff --git a/flutter_app/pubspec.yaml b/flutter_app/pubspec.yaml new file mode 100644 index 0000000..010a7bc --- /dev/null +++ b/flutter_app/pubspec.yaml @@ -0,0 +1,20 @@ +name: pozo_app +description: "A premium billing onboarding and setup flow for Indian MSMEs built with Flutter." +version: 1.0.0+1 + +environment: + sdk: ">=3.0.0 <4.0.0" + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.5 + google_fonts: ^5.1.0 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 + +flutter: + uses-material-design: true diff --git a/flutter_app/test/widget_test.dart b/flutter_app/test/widget_test.dart new file mode 100644 index 0000000..9cce04a --- /dev/null +++ b/flutter_app/test/widget_test.dart @@ -0,0 +1,30 @@ +// 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:pozo_app/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const PozoApp()); + + // 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/flutter_app/web/favicon.png b/flutter_app/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/flutter_app/web/favicon.png differ diff --git a/flutter_app/web/icons/Icon-192.png b/flutter_app/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/flutter_app/web/icons/Icon-192.png differ diff --git a/flutter_app/web/icons/Icon-512.png b/flutter_app/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/flutter_app/web/icons/Icon-512.png differ diff --git a/flutter_app/web/icons/Icon-maskable-192.png b/flutter_app/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/flutter_app/web/icons/Icon-maskable-192.png differ diff --git a/flutter_app/web/icons/Icon-maskable-512.png b/flutter_app/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/flutter_app/web/icons/Icon-maskable-512.png differ diff --git a/flutter_app/web/index.html b/flutter_app/web/index.html new file mode 100644 index 0000000..ba5eaa9 --- /dev/null +++ b/flutter_app/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + pozo_app + + + + + + diff --git a/flutter_app/web/manifest.json b/flutter_app/web/manifest.json new file mode 100644 index 0000000..037d8f0 --- /dev/null +++ b/flutter_app/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "pozo_app", + "short_name": "pozo_app", + "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/index.html b/index.html new file mode 100644 index 0000000..21dfe69 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + My Google AI Studio App + + +
+ + + + diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..3611573 --- /dev/null +++ b/metadata.json @@ -0,0 +1 @@ +{"name":"Pozo Modern Billing","description":"A premium, high-fidelity interactive billing onboarding and setup flow designed for Indian MSMEs.","requestFramePermissions":[],"majorCapabilities":["MAJOR_CAPABILITY_SERVER_SIDE_GEMINI_API"]} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..52d4e9e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4284 @@ +{ + "name": "react-example", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "react-example", + "version": "0.0.0", + "dependencies": { + "@google/genai": "^2.4.0", + "@tailwindcss/vite": "^4.1.14", + "@vitejs/plugin-react": "^5.0.4", + "dotenv": "^17.2.3", + "express": "^4.21.2", + "lucide-react": "^0.546.0", + "motion": "^12.23.24", + "react": "^19.0.1", + "react-dom": "^19.0.1", + "vite": "^6.2.3" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "@types/node": "^22.14.0", + "autoprefixer": "^10.4.21", + "esbuild": "^0.25.0", + "tailwindcss": "^4.1.14", + "tsx": "^4.21.0", + "typescript": "~5.8.2", + "vite": "^6.2.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/genai": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-2.8.0.tgz", + "integrity": "sha512-pc2ayxqO5+O7AvnHBqpNHIk7PAZkHZgL31tbyx0gJZBSS9qPYiQoqwK7oYOw/ePmG6QY4EMSu+304vD5QlhXAw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", + "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "license": "BSD-3-Clause" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", + "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.21.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", + "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-arm64": "4.3.0", + "@tailwindcss/oxide-darwin-x64": "4.3.0", + "@tailwindcss/oxide-freebsd-x64": "4.3.0", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", + "@tailwindcss/oxide-linux-x64-musl": "4.3.0", + "@tailwindcss/oxide-wasm32-wasi": "4.3.0", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", + "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", + "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", + "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", + "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz", + "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.0", + "@tailwindcss/oxide": "4.3.0", + "tailwindcss": "4.3.0" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.20.tgz", + "integrity": "sha512-6tELRwSDYWW9EdZhbeZmYGZ1/7Djkt+Ah3/ScEYT9cDord7UJzasR/4D3VONg9tQI5CDp+/CZC1AXj2pCFOvpw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.35", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.35.tgz", + "integrity": "sha512-honAfLBde0HAFLdNyBEfuuENkF6zR+ozxqxa/2zJKHBe1qzLqyTSeRKpdPEHAP03rlDGyQOPnCSxnVpVqQo9Mg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", + "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.371", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.371.tgz", + "integrity": "sha512-e9htk9mAYL6AzmkEhSvVVw7IWGSBJ/Bqdn2eRyRLrj1g6sncN4WbFt5qnILYoCktktr45pyjIrOiRvBThQ808w==", + "license": "ISC" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz", + "integrity": "sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.40.0.tgz", + "integrity": "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.40.0", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.5.tgz", + "integrity": "sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/google-auth-library": { + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.7.0.tgz", + "integrity": "sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.546.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.546.0.tgz", + "integrity": "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/motion": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.40.0.tgz", + "integrity": "sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA==", + "license": "MIT", + "dependencies": { + "framer-motion": "^12.40.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "12.40.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.40.0.tgz", + "integrity": "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-releases": { + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/protobufjs": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.3.tgz", + "integrity": "sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rollup": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", + "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..44745ed --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "react-example", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --port=3000 --host=0.0.0.0", + "build": "vite build", + "preview": "vite preview", + "clean": "rm -rf dist server.js", + "lint": "tsc --noEmit" + }, + "dependencies": { + "@google/genai": "^2.4.0", + "@tailwindcss/vite": "^4.1.14", + "@vitejs/plugin-react": "^5.0.4", + "lucide-react": "^0.546.0", + "react": "^19.0.1", + "react-dom": "^19.0.1", + "vite": "^6.2.3", + "express": "^4.21.2", + "dotenv": "^17.2.3", + "motion": "^12.23.24" + }, + "devDependencies": { + "@types/node": "^22.14.0", + "autoprefixer": "^10.4.21", + "esbuild": "^0.25.0", + "tailwindcss": "^4.1.14", + "tsx": "^4.21.0", + "typescript": "~5.8.2", + "vite": "^6.2.3", + "@types/express": "^4.17.21" + } +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..9ff2c9f --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,153 @@ +import React, { useState } from 'react'; +import DeviceFrame from './components/DeviceFrame'; +import WelcomeScreen from './components/WelcomeScreen'; +import MobileLoginScreen from './components/MobileLoginScreen'; +import OtpVerificationScreen from './components/OtpVerificationScreen'; +import BusinessSetupScreen from './components/BusinessSetupScreen'; +import CustomizeSetupScreen from './components/CustomizeSetupScreen'; +import SetupCompleteScreen from './components/SetupCompleteScreen'; +import BillingDashboard from './components/BillingDashboard'; +import { OnboardingState, BusinessFeatures } from './types'; + +export default function App() { + // Initialize standard global onboarding states + const [state, setState] = useState({ + step: 'welcome', + mobileNumber: '', + otpCode: ['', '', '', '', '', ''], + businessName: '', + businessType: 'supermarket', + gstin: '', + features: { + barcodeScanner: false, + kotManagement: false, + inventoryAlerts: true // Pre-checked by default as depicted in Screen 5 + } + }); + + const handleReset = () => { + setState({ + step: 'welcome', + mobileNumber: '', + otpCode: ['', '', '', '', '', ''], + businessName: '', + businessType: 'supermarket', + gstin: '', + features: { + barcodeScanner: false, + kotManagement: false, + inventoryAlerts: true + } + }); + }; + + const handleWelcomeDone = () => { + setState(prev => ({ ...prev, step: 'mobile-login' })); + }; + + const handleMobileSubmitted = (mobile: string) => { + setState(prev => ({ ...prev, mobileNumber: mobile, step: 'otp-verification' })); + }; + + const handleOtpVerified = (otp: string[]) => { + setState(prev => ({ ...prev, otpCode: otp, step: 'business-setup' })); + }; + + const handleBusinessSubmitted = (data: { businessName: string; businessType: string; gstin: string }) => { + setState(prev => ({ + ...prev, + businessName: data.businessName, + businessType: data.businessType, + gstin: data.gstin, + step: 'customize-setup' + })); + }; + + const handleFeaturesCustomized = (features: BusinessFeatures) => { + setState(prev => ({ ...prev, features, step: 'setup-complete' })); + }; + + const handleBypassFeatures = () => { + setState(prev => ({ ...prev, step: 'setup-complete' })); + }; + + const handleOnboardingFinished = () => { + setState(prev => ({ ...prev, step: 'setup-complete' as any })); // Trigger direct ledger launch + // To route to Billing Register, we'll assign a simulated custom state 'billing-dashboard' + setState(prev => ({ ...prev, step: 'billing-dashboard' as any })); + }; + + // Switch router for the multi-stage form wizard + const renderStepContent = () => { + switch (state.step) { + case 'welcome': + return ( + + ); + case 'mobile-login': + return ( + setState(prev => ({ ...prev, step: 'welcome' }))} + onContinue={handleMobileSubmitted} + state={state} + /> + ); + case 'otp-verification': + return ( + setState(prev => ({ ...prev, step: 'mobile-login' }))} + onContinue={handleOtpVerified} + state={state} + /> + ); + case 'business-setup': + return ( + setState(prev => ({ ...prev, step: 'otp-verification' }))} + onContinue={handleBusinessSubmitted} + state={state} + /> + ); + case 'customize-setup': + return ( + setState(prev => ({ ...prev, step: 'business-setup' }))} + onSkip={handleBypassFeatures} + onContinue={handleFeaturesCustomized} + state={state} + /> + ); + case 'setup-complete': + return ( + + ); + // Custom Post-onboarding functional simulator route + case 'billing-dashboard' as any: + return ( + + ); + default: + return ( + + ); + } + }; + + return ( + + {renderStepContent()} + + ); +} diff --git a/src/components/BillingDashboard.tsx b/src/components/BillingDashboard.tsx new file mode 100644 index 0000000..7d85ceb --- /dev/null +++ b/src/components/BillingDashboard.tsx @@ -0,0 +1,500 @@ +import React, { useState } from 'react'; +import { Plus, Minus, ShoppingCart, ArrowLeft, RefreshCw, Layers, Sparkles, Receipt, Camera, Printer, CheckCircle2, ShieldCheck } from 'lucide-react'; +import { OnboardingState } from '../types'; + +interface BillingDashboardProps { + state: OnboardingState; + onReset: () => void; +} + +interface ProductItem { + id: string; + name: string; + price: number; + stock: number; + code: string; +} + +interface BillingItem { + product: ProductItem; + quantity: number; +} + +const INVENTORY_PRESETS: Record = { + supermarket: [ + { id: 'sm1', name: 'Premium Basmati Rice (1kg)', price: 120, stock: 45, code: '89012300052' }, + { id: 'sm2', name: 'Fresh Farm Milk (1L)', price: 65, stock: 2, code: '89045300010' }, + { id: 'sm3', name: 'Refined Cooking Oil (1L)', price: 165, stock: 18, code: '89010320491' }, + { id: 'sm4', name: 'Refined White Sugar (1kg)', price: 48, stock: 3, code: '89034200421' }, + { id: 'sm5', name: 'Organic Green T-Tea (250g)', price: 110, stock: 24, code: '89512300011' }, + { id: 'sm6', name: 'Whole Wheat Atta (5kg)', price: 230, stock: 7, code: '89011210042' } + ], + restaurant: [ + { id: 'rt1', name: 'Fresh Paneer Butter Masala', price: 240, stock: 19, code: '9901230' }, + { id: 'rt2', name: 'Butter Tandoori Naan', price: 45, stock: 15, code: '9904530' }, + { id: 'rt3', name: 'Dum Veg Biryani Deluxe', price: 190, stock: 2, code: '9901032' }, + { id: 'rt4', name: 'Crispy Butter Masala Dosa', price: 90, stock: 22, code: '9903420' }, + { id: 'rt5', name: 'Rich Chocolate Milkshake', price: 120, stock: 3, code: '9951230' }, + { id: 'rt6', name: 'Hot Roasted Filter Coffee', price: 50, stock: 30, code: '9901121' } + ], + clothing: [ + { id: 'cl1', name: 'Premium Oxford Cotton Shirt', price: 899, stock: 8, code: '77012301' }, + { id: 'cl2', name: 'Slim Fit Dark Jeans', price: 1599, stock: 2, code: '77045302' }, + { id: 'cl3', name: 'Designer Summer Slip Dress', price: 1299, stock: 5, code: '77010323' }, + { id: 'cl4', name: 'Graphic Printed Tee-Shirt', price: 450, stock: 40, code: '77034204' }, + { id: 'cl5', name: 'Breathable Sports Sneakers', price: 1899, stock: 3, code: '77512305' }, + { id: 'cl6', name: 'Stitch Leather Belt Brown', price: 349, stock: 12, code: '77011216' } + ], + kirana: [ + { id: 'kr1', name: 'Premium Toor Dal (1kg)', price: 145, stock: 15, code: '4401230' }, + { id: 'kr2', name: 'Iodized Powdered Salt (1kg)', price: 22, stock: 50, code: '4404530' }, + { id: 'kr3', name: 'Herbal Moisturizer Soap', price: 42, stock: 2, code: '4401032' }, + { id: 'kr4', name: 'Anti-Germ Toothpaste (200g)', price: 85, stock: 16, code: '4403420' }, + { id: 'kr5', name: 'Dishwash Cleaning Soap', price: 25, stock: 3, code: '4451230' }, + { id: 'kr6', name: 'Red Chili Powder (200g)', price: 65, stock: 18, code: '4401121' } + ], + others: [ + { id: 'ot1', name: 'Utility Household Scrubber', price: 35, stock: 33, code: '5501230' }, + { id: 'ot2', name: 'AAA Rechargeable Batteries', price: 120, stock: 4, code: '5504530' }, + { id: 'ot3', name: 'LED High Bright Focus Bulb', price: 140, stock: 2, code: '5501032' }, + { id: 'ot4', name: 'Water Bottle Stainless (1L)', price: 320, stock: 11, code: '5503420' }, + { id: 'ot5', name: 'Microfiber Floor Duster', price: 75, stock: 24, code: '5551230' }, + { id: 'ot6', name: 'Multi-plug Protection Adapter', price: 240, stock: 9, code: '5501121' } + ] +}; + +export default function BillingDashboard({ state, onReset }: BillingDashboardProps) { + const currentCategory = state.businessType || 'supermarket'; + const products = INVENTORY_PRESETS[currentCategory] || INVENTORY_PRESETS.supermarket; + + const [billingList, setBillingList] = useState([]); + const [printingInvoice, setPrintingInvoice] = useState(false); + const [invoiceNumber, setInvoiceNumber] = useState('POZO-26402'); + const [scanMessage, setScanMessage] = useState(''); + + const handleAddItem = (product: ProductItem) => { + const existing = billingList.find((item) => item.product.id === product.id); + if (existing) { + if (existing.quantity >= product.stock && state.features?.inventoryAlerts) { + alert(`Cannot add more. Inventory limit reached for ${product.name}!`); + return; + } + setBillingList( + billingList.map((item) => + item.product.id === product.id + ? { ...item, quantity: item.quantity + 1 } + : item + ) + ); + } else { + setBillingList([...billingList, { product, quantity: 1 }]); + } + }; + + const handleRemoveOne = (productId: string) => { + const existing = billingList.find((item) => item.product.id === productId); + if (existing && existing.quantity > 1) { + setBillingList( + billingList.map((item) => + item.product.id === productId + ? { ...item, quantity: item.quantity - 1 } + : item + ) + ); + } else { + setBillingList(billingList.filter((item) => item.product.id !== productId)); + } + }; + + // Simulating Barcode scanning if enabled + const simulateBarcodeScan = () => { + if (!state.features?.barcodeScanner) return; + + // Pick a random product from inventory catalog + const randomProduct = products[Math.floor(Math.random() * products.length)]; + handleAddItem(randomProduct); + + setScanMessage(`🎯 Scanned EAN Barcode [${randomProduct.code}] - Added ${randomProduct.name}!`); + setTimeout(() => { + setScanMessage(''); + }, 3500); + }; + + // Reset actual register + const clearRegister = () => { + setBillingList([]); + }; + + // Financial calculations + const subtotal = billingList.reduce((acc, item) => acc + item.product.price * item.quantity, 0); + const hasGstin = state.gstin && state.gstin.trim().length > 0; + + // 18% GST (9% CGST + 9% SGST) split if GSTIN specified + const cgstRate = 0.09; + const sgstRate = 0.09; + const cgst = hasGstin ? subtotal * cgstRate : 0; + const sgst = hasGstin ? subtotal * sgstRate : 0; + const total = subtotal + cgst + sgst; + + const handlePrint = () => { + const randNum = `POZO-${Math.floor(10000 + Math.random() * 90000)}`; + setInvoiceNumber(randNum); + setPrintingInvoice(true); + }; + + const closeReceiptAndReset = () => { + setPrintingInvoice(false); + clearRegister(); + }; + + return ( +
+ + {/* Dynamic Header */} +
+
+
+ P +
+
+

+ {state.businessName || 'Sharma General Store'} +

+

+ + Live Register +

+
+
+ + {/* Feature status indicators on top bar */} +
+ {state.features?.barcodeScanner && ( + + )} + + {state.features?.kotManagement && ( + + KOT Active + + )} + + +
+
+ + {/* Barcode feedback banner */} + {scanMessage && ( +
+ + {scanMessage} +
+ )} + + {/* Content Columns layout */} +
+ + {/* Left: Product Catalog layout */} +
+
+

Store Catalog

+ + {currentCategory} preset + +
+ +
+ {products.map((prod) => { + const currentInCart = billingList.find(b => b.product.id === prod.id); + const countInCart = currentInCart?.quantity || 0; + const isLowStock = state.features?.inventoryAlerts && (prod.stock - countInCart) <= 3; + const remainingStock = prod.stock - countInCart; + + return ( + + ); + })} +
+
+ + {/* Right: Checkout Ledger Tray */} +
+
+
+

+ + Billing Tray ({billingList.length}) +

+ + {billingList.length > 0 && ( + + )} +
+ + {/* Selected products scroll tray */} +
+ {billingList.length === 0 ? ( +
+
+ +
+

No products selected from Catalog above.

+

Click catalog items to start ledger computations.

+
+ ) : ( + billingList.map((item) => ( +
+
+

{item.product.name}

+ ₹{item.product.price} × {item.quantity} +
+ + {/* Quantity controls */} +
+ + {item.quantity} + +
+
+ )) + )} +
+
+ + {/* Checkout pricing sum list */} +
+
+
+ Subtotal + ₹{subtotal.toFixed(2)} +
+ + {hasGstin && ( + <> +
+ CGST (9.0%) + ₹{cgst.toFixed(2)} +
+
+ SGST (9.0%) + ₹{sgst.toFixed(2)} +
+ + )} + +
+ +
+ Grand Total + ₹{total.toFixed(2)} +
+
+ + +
+
+
+ + {/* High Fidelity Printable thermal invoice popup */} + {printingInvoice && ( +
+
+ + {/* Bill receipt frame */} +
+ + {/* Receipt Header logo */} +
+

{state.businessName || 'Sharma General Store'}

+

{currentCategory} Service Center

+ {hasGstin && ( +

+ GSTIN: {state.gstin} +

+ )} +
+ + {/* Dividing dash lines */} +
+ + {/* Receipt details columns */} +
+
+ Invoice No: + {invoiceNumber} +
+
+ Date Track: + {new Date().toLocaleDateString('en-IN')} +
+
+ Terminal Class: + Web App Counter +
+
+ + {/* Dash */} +
+ + {/* Table labels */} +
+ Item Description + Qty + Total +
+ + {/* Items row columns */} +
+ {billingList.map(b => ( +
+ {b.product.name} + ×{b.quantity} + ₹{b.product.price * b.quantity} +
+ ))} +
+ + {/* Dash */} +
+ + {/* Pricing ledger splits */} +
+
+ Cart Amount: + ₹{subtotal.toFixed(2)} +
+ {hasGstin && ( + <> +
+ CGST (9%): + ₹{cgst.toFixed(2)} +
+
+ SGST (9%): + ₹{sgst.toFixed(2)} +
+ + )} +
+
+ NET TOTAL: + ₹{total.toFixed(2)} +
+
+ + {/* Receipt Footer */} +
+
+

Thank You For Your Patronage!

+
+ + Powered by PozoApp +
+
+
+ + {/* Print trigger actions */} +
+ + + +
+ +
+
+ )} + +
+ ); +} diff --git a/src/components/BusinessSetupScreen.tsx b/src/components/BusinessSetupScreen.tsx new file mode 100644 index 0000000..ac969bf --- /dev/null +++ b/src/components/BusinessSetupScreen.tsx @@ -0,0 +1,641 @@ +import React, { useState } from 'react'; +import { + ArrowLeft, ShoppingCart, UtensilsCrossed, Shirt, ShoppingBag, LayoutGrid, HelpCircle, + Store, MapPin, Camera, Check, ChevronRight, FileText, Utensils, Award, CreditCard, + UploadCloud, X, Image as ImageIcon +} from 'lucide-react'; +import { OnboardingState, BUSINESS_TYPES } from '../types'; + +interface BusinessSetupProps { + onBack: () => void; + onContinue: (data: { businessName: string; businessType: string; gstin: string }) => void; + state: OnboardingState; +} + +export default function BusinessSetupScreen({ onBack, onContinue, state }: BusinessSetupProps) { + const [name, setName] = useState(state.businessName || ''); + const [type, setType] = useState(state.businessType || 'supermarket'); + const [gstin, setGstin] = useState(state.gstin || ''); + const [errorHeader, setErrorHeader] = useState(''); + + // High-fidelity interactive state matching and extending spec + const [selectedDocs, setSelectedDocs] = useState(['GSTIN', 'FSSAI']); + const [detectedLocation, setDetectedLocation] = useState(''); + const [facadePhotoUploaded, setFacadePhotoUploaded] = useState(false); + const [gstinVerified, setGstinVerified] = useState(false); + const [toastMessage, setToastMessage] = useState(''); + + // Interactive local states for each optional document form + const [docNumbers, setDocNumbers] = useState>({ + GSTIN: state.gstin || '', + FSSAI: '', + Aadhar: '', + 'Udhyog Aadhar': '', + PAN: '' + }); + + const [uploadedDocs, setUploadedDocs] = useState>({}); + + const triggerToast = (msg: string) => { + setToastMessage(msg); + setTimeout(() => { + setToastMessage(''); + }, 3200); + }; + + const handleNameChange = (e: React.ChangeEvent) => { + setName(e.target.value); + if (e.target.value.trim()) { + setErrorHeader(''); + } + }; + + const handleGstinChange = (e: React.ChangeEvent) => { + const value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, ''); + if (value.length <= 15) { + setGstin(value); + setDocNumbers(prev => ({ ...prev, GSTIN: value })); + } + }; + + const handleDocNumberChange = (doc: string, val: string) => { + setDocNumbers(prev => ({ ...prev, [doc]: val })); + if (doc === 'GSTIN') { + setGstin(val.toUpperCase().replace(/[^A-Z0-9]/g, '')); + } + }; + + const toggleDoc = (doc: string) => { + if (selectedDocs.includes(doc)) { + setSelectedDocs(prev => prev.filter(d => d !== doc)); + } else { + setSelectedDocs(prev => [...prev, doc]); + } + // Simple haptic feedback simulation + if (window.navigator && window.navigator.vibrate) { + window.navigator.vibrate(20); + } + }; + + const handleMockUpload = (doc: string) => { + const mockFileNames: Record = { + GSTIN: 'gst_certificate_signed.pdf', + FSSAI: 'fssai_license_verified.pdf', + Aadhar: 'aadhar_card_front_back.jpg', + 'Udhyog Aadhar': 'msme_reg_certificate.pdf', + PAN: 'pan_card_copy_cropped.jpg' + }; + + setUploadedDocs(prev => ({ + ...prev, + [doc]: mockFileNames[doc] || 'document_uploaded.pdf' + })); + triggerToast(`📸 ${doc} proof attached successfully!`); + }; + + const clearDocUpload = (doc: string) => { + setUploadedDocs(prev => { + const copy = { ...prev }; + delete copy[doc]; + return copy; + }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!name.trim()) { + setErrorHeader('Please specify your Business/Shop Name'); + return; + } + onContinue({ businessName: name.trim(), businessType: type, gstin }); + }; + + const getCategoryIcon = (id: string, isSelected: boolean) => { + const sizeClass = "w-7 h-7 stroke-[1.8]"; + const colorClass = isSelected ? "text-primary" : "text-on-surface-variant"; + + switch (id) { + case 'supermarket': + return ; + case 'restaurant': + return ; + case 'clothing': + return ; + case 'kirana': + return ; + case 'grocers': + return ; + case 'others': + default: + return ; + } + }; + + const isFormValid = name.trim().length > 0; + + return ( +
+ {/* App bar */} +
+ + PozoApp + Step 3 of 5 +
+ + {/* Progress slider bar: 60% filled */} +
+
+
+ + {/* Toast Alert */} + {toastMessage && ( +
+ {toastMessage} +
+ )} + + {/* Form Area */} +
+
+ {/* Header titles */} +
+

Complete verification

+

+ Verify your business details to start selling. +

+
+ + {/* Form details */} +
+ {/* Input 1: Shop Name */} +
+ + + {errorHeader &&

{errorHeader}

} +
+ + {/* Input 2: Business Type Selection Grid */} +
+ + +
+ {BUSINESS_TYPES.map((cat) => { + const isSelected = type === cat.id; + return ( + + ); + })} +
+
+ + {/* Input 3: GSTIN (With Verify Button) */} +
+
+ + Optional +
+ +
+ + +
+ +

+ + Auto-fetches address & legal name on verification. +

+
+ + {/* Input 4: Shop Location Detect */} +
+ + + +
+ + {/* Input 5: Identity Proof Section - WITH SELECT ALL THAT APPLY & CUSTOM ICONS */} +
+ + +
+ {[ + { name: 'GSTIN', icon: 'FileText' }, + { name: 'FSSAI', icon: 'Utensils' }, + { name: 'Aadhar', icon: 'Award' }, + { name: 'Udhyog Aadhar', icon: 'Store' }, + { name: 'PAN', icon: 'CreditCard' } + ].map((doc) => { + const isSelected = selectedDocs.includes(doc.name); + return ( + + ); + })} +
+ + {/* Dynamic Subforms Containers matching the collapsed/expanded design */} +
+ + {/* GSTIN Details Container */} + {selectedDocs.includes('GSTIN') && ( +
+
+ + GSTIN Details + + +
+
+ handleDocNumberChange('GSTIN', e.target.value)} + className="h-[46px] px-3.5 rounded-lg border border-outline bg-surface-container-lowest text-on-surface font-sans text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-outline-variant" + /> + + {uploadedDocs.GSTIN ? ( +
+ + + {uploadedDocs.GSTIN} + + +
+ ) : ( + + )} +
+
+ )} + + {/* FSSAI Details Container */} + {selectedDocs.includes('FSSAI') && ( +
+
+ + FSSAI License Details + + +
+
+ handleDocNumberChange('FSSAI', e.target.value)} + className="h-[46px] px-3.5 rounded-lg border border-outline bg-surface-container-lowest text-on-surface font-sans text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-outline-variant" + /> + + {uploadedDocs.FSSAI ? ( +
+ + + {uploadedDocs.FSSAI} + + +
+ ) : ( + + )} +
+
+ )} + + {/* Aadhar Details Container */} + {selectedDocs.includes('Aadhar') && ( +
+
+ + Aadhar Card Details + + +
+
+ handleDocNumberChange('Aadhar', e.target.value.replace(/\D/g, ''))} + className="h-[46px] px-3.5 rounded-lg border border-outline bg-surface-container-lowest text-on-surface font-sans text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-outline-variant" + /> + + {uploadedDocs.Aadhar ? ( +
+ + + {uploadedDocs.Aadhar} + + +
+ ) : ( + + )} +
+
+ )} + + {/* MSME Details Container */} + {selectedDocs.includes('Udhyog Aadhar') && ( +
+
+ + MSME (Udhyog Aadhar) + + +
+
+ handleDocNumberChange('Udhyog Aadhar', e.target.value)} + className="h-[46px] px-3.5 rounded-lg border border-outline bg-surface-container-lowest text-on-surface font-sans text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-outline-variant" + /> + + {uploadedDocs['Udhyog Aadhar'] ? ( +
+ + + {uploadedDocs['Udhyog Aadhar']} + + +
+ ) : ( + + )} +
+
+ )} + + {/* PAN Details Container */} + {selectedDocs.includes('PAN') && ( +
+
+ + PAN Card Details + + +
+
+ handleDocNumberChange('PAN', e.target.value.toUpperCase())} + className="h-[46px] px-3.5 rounded-lg border border-outline bg-surface-container-lowest text-on-surface font-sans text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary placeholder:text-outline-variant uppercase" + /> + + {uploadedDocs.PAN ? ( +
+ + + {uploadedDocs.PAN} + + +
+ ) : ( + + )} +
+
+ )} + +
+
+ + {/* Input 6: Shop Facade Photo Upload Area */} +
+ + +
+ { + if (e.target.files && e.target.files.length > 0) { + setFacadePhotoUploaded(true); + triggerToast('📸 Front view photo captured successfully!'); + } + }} + className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10" + /> + +
+
+ {facadePhotoUploaded ? : } +
+
+ + {facadePhotoUploaded ? 'Front View Uploaded' : 'Upload front view'} + + + {facadePhotoUploaded ? 'Click or Drag to replace photo' : 'Clear photo showing shop board'} + +
+
+
+
+
+
+
+ + {/* Pinned Action zone */} +
+
+ +
+
+
+ ); +} diff --git a/src/components/CustomizeSetupScreen.tsx b/src/components/CustomizeSetupScreen.tsx new file mode 100644 index 0000000..f5b4a89 --- /dev/null +++ b/src/components/CustomizeSetupScreen.tsx @@ -0,0 +1,178 @@ +import React, { useState } from 'react'; +import { ArrowLeft, Settings, Scan, ReceiptText, Package, Check } from 'lucide-react'; +import { OnboardingState, BusinessFeatures } from '../types'; + +interface CustomizeSetupProps { + onBack: () => void; + onSkip: () => void; + onContinue: (features: BusinessFeatures) => void; + state: OnboardingState; +} + +export default function CustomizeSetupScreen({ onBack, onSkip, onContinue, state }: CustomizeSetupProps) { + const [barcode, setBarcode] = useState(state.features?.barcodeScanner ?? false); + const [kot, setKot] = useState(state.features?.kotManagement ?? false); + const [inventory, setInventory] = useState(state.features?.inventoryAlerts ?? true); + + const handleSubmit = () => { + onContinue({ + barcodeScanner: barcode, + kotManagement: kot, + inventoryAlerts: inventory + }); + }; + + return ( +
+ {/* Top Header Navigation */} +
+
+ + PozoApp +
+ +
+ + {/* Progress sliding bar: 80% filled (4 of 5 segments active) */} +
+
+
+
+
+
+
+ +
+ Step 4 of 5 + Smart Setup +
+ + {/* Toggles Container stream */} +
+
+ {/* Header titles */} +
+

Customize Your Setup

+

+ Turn on the features you need for your shop. You can always change these later in settings. +

+
+ + {/* List of custom feature toggle cards */} +
+ {/* Card 1: Barcode Scanner */} +
+
+
+ +
+
+

Barcode Scanner

+

Do you use a Barcode Scanner?

+
+
+ + {/* Custom interactive Switch element */} + +
+ + {/* Card 2: KOT Management */} +
+
+
+ +
+
+

KOT Management

+

Do you need Kitchen Order Ticket management?

+
+
+ + {/* Custom Switch element */} + +
+ + {/* Card 3: Inventory Alerts */} +
+
+
+ +
+
+

Inventory Alerts

+

Get notified when stock is running low.

+
+
+ + {/* Custom Switch element (pre-checked, with a mini check inside handle) */} + +
+
+
+
+ + {/* Pinned Bottom action */} +
+
+ + + +
+
+
+ ); +} diff --git a/src/components/DeviceFrame.tsx b/src/components/DeviceFrame.tsx new file mode 100644 index 0000000..96341dd --- /dev/null +++ b/src/components/DeviceFrame.tsx @@ -0,0 +1,144 @@ +import React, { useState, useEffect } from 'react'; +import { Wifi, Battery, Signal, RefreshCw, Smartphone, Monitor, Info } from 'lucide-react'; + +interface DeviceFrameProps { + children: React.ReactNode; + onReset: () => void; + className?: string; +} + +export default function DeviceFrame({ children, onReset, className = '' }: DeviceFrameProps) { + const [isFullscreen, setIsFullscreen] = useState(false); + const [time, setTime] = useState('12:30'); + + useEffect(() => { + // Standard system clock updates in high fidelity status bar + const updateTime = () => { + const now = new Date(); + let hours = now.getHours(); + const minutes = now.getMinutes().toString().padStart(2, '0'); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12 || 12; + setTime(`${hours}:${minutes} ${ampm}`); + }; + updateTime(); + const interval = setInterval(updateTime, 1000 * 30); + return () => clearInterval(interval); + }, []); + + return ( +
+ {/* Simulation HUD bar */} +
+
+
+ P +
+
+

+ PozoApp Live Simulator + Interactive Demo +

+

Realistic state synchronization between configuration pages

+
+
+ +
+ {/* Layout switches */} + + + + +
+ + {/* Reset Demo State button */} + +
+
+ + {isFullscreen ? ( + /* Full-screen Fluid responsive container */ +
+ {children} +
+ ) : ( + /* Physical Mobile Smartphone frame mockup */ +
+ {/* Speaker, camera notch, face ID pill */} +
+
+
+
+
+
+ + /* Inner Dynamic viewport */ +
+ {/* Standard status bar */} +
+ {time.split(' ')[0]} + +
+ + 5G + +
+ 100% + +
+
+
+ + {/* Simulated Content stream wrapper */} +
+ {children} +
+ + {/* Virtual bottom navigation slider bar (iOS/Android home stroke) */} +
+
+
+ )} + + {/* Embedded documentation card inside preview */} +
+ +

+ Flutter Dart classes are also auto-generated inside this workspace at /flutter_app/ for cross-platform Android, iOS and Web compilations. +

+
+
+ ); +} diff --git a/src/components/MobileLoginScreen.tsx b/src/components/MobileLoginScreen.tsx new file mode 100644 index 0000000..466d15f --- /dev/null +++ b/src/components/MobileLoginScreen.tsx @@ -0,0 +1,213 @@ +import React, { useState } from 'react'; +import { ArrowLeft, Lock, MessageSquare, ShieldCheck, Zap, Shield } from 'lucide-react'; +import { OnboardingState } from '../types'; + +interface MobileLoginProps { + onBack: () => void; + onContinue: (mobile: string) => void; + state: OnboardingState; +} + +export default function MobileLoginScreen({ onBack, onContinue, state }: MobileLoginProps) { + const [mobile, setMobile] = useState(state.mobileNumber || ''); + const [error, setError] = useState(''); + + // Validate Indian Phone standard format + const handleChange = (e: React.ChangeEvent) => { + const value = e.target.value.replace(/\D/g, ''); // Numeric only + if (value.length <= 10) { + setMobile(value); + if (value.length === 10) { + setError(''); + } + } + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (mobile.length !== 10) { + setError('Please enter a valid 10-digit mobile number'); + return; + } + setError(''); + onContinue(mobile); + }; + + const handleTruecallerVerify = () => { + setMobile('9876543210'); + setError(''); + // Simulate instant verification redirect/transition + setTimeout(() => { + onContinue('9876543210'); + }, 500); + }; + + const isValid = mobile.length === 10; + + return ( +
+ {/* Top Application Header Bar */} +
+ + PozoApp +
{/* Spacer to keep title left-ish / aligned */} +
+ + {/* Primary scrollable Form view */} +
+ {/* 1. Progress Bar Step Label & Bar */} +
+
+ Step 2 of 5 + Mobile Login +
+
+
+
+
+
+
+
+
+ + {/* Welcome titles */} +
+

Welcome Back

+

+ Enter your mobile number to sign in or create a new account. +

+ + {/* 6. Top Badge: Green "Secure OTP Verification" chip with lock icon */} +
+ + Secure OTP Verification +
+
+ + {/* 2. Truecaller Card */} +
+
+
+ +
+
+ Verify instantly with + Truecaller +
+
+ +
+ +91 98765 43210 + + + +

+ No OTP required. Your phone will be verified automatically. +

+
+
+ + {/* 3. Divider: "Or enter mobile number manually" */} +
+
+ + Or enter mobile number manually + +
+
+ + {/* 4. Mobile Number input field */} +
+ + +
+ + {/* Country flag box */} +
+ India Flag + +91 +
+ + {/* Telephone input box */} + +
+ + {error && ( +

{error}

+ )} + + {/* Quick preset hint helper to expedite testing */} +
+

+ + You can enter any 10 digits (e.g. 9876543210) to simulate. An automated SMS OTP will trigger next. +

+
+
+
+ + {/* 5. Sticky Bottom Actions zone */} +
+
+ {/* Full width red "Send OTP" button */} + + + {/* Outline style red "Help / Talk to Support" button */} + +
+
+
+ ); +} diff --git a/src/components/OtpVerificationScreen.tsx b/src/components/OtpVerificationScreen.tsx new file mode 100644 index 0000000..46b0d65 --- /dev/null +++ b/src/components/OtpVerificationScreen.tsx @@ -0,0 +1,298 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { ArrowLeft, Clock, MessageCircle, HelpCircle, Save, ArrowRight, MessageSquareCode } from 'lucide-react'; +import { OnboardingState } from '../types'; + +interface OtpVerificationProps { + onBack: () => void; + onContinue: (otp: string[]) => void; + state: OnboardingState; +} + +export default function OtpVerificationScreen({ onBack, onContinue, state }: OtpVerificationProps) { + const [digits, setDigits] = useState(['', '', '', '', '', '']); + const [timeLeft, setTimeLeft] = useState(45); + const [showNotification, setShowNotification] = useState(false); + const [focusIndex, setFocusIndex] = useState(0); + const inputRefs = useRef([]); + + // Real-time OTP count-down clock simulation + useEffect(() => { + if (timeLeft <= 0) return; + const timer = setInterval(() => { + setTimeLeft((prev) => prev - 1); + }, 1000); + return () => clearInterval(timer); + }, [timeLeft]); + + // Push SMS banner trigger after 2 seconds for high fidelity demo + useEffect(() => { + const pushTimer = setTimeout(() => { + setShowNotification(true); + }, 2000); + return () => clearTimeout(pushTimer); + }, []); + + const handleDigitChange = (index: number, value: string) => { + const val = value.replace(/\D/g, '').slice(-1); // Only allow last digit written + const updated = [...digits]; + updated[index] = val; + setDigits(updated); + + // Auto focus next box + if (val && index < 5) { + setFocusIndex(index + 1); + inputRefs.current[index + 1]?.focus(); + } + }; + + const handleKeyDown = (index: number, e: React.KeyboardEvent) => { + if (e.key === 'Backspace' && !digits[index] && index > 0) { + const updated = [...digits]; + updated[index - 1] = ''; + setDigits(updated); + setFocusIndex(index - 1); + inputRefs.current[index - 1]?.focus(); + } + }; + + const triggerResend = () => { + setTimeLeft(45); + }; + + // Automated typing simulator on SMS Click + const autoDetectOtpAction = () => { + const sampleCode = ['9', '4', '3', '7', '1', '5']; + + // Type out digits dynamically for user delight + sampleCode.forEach((char, idx) => { + setTimeout(() => { + setDigits((prev) => { + const next = [...prev]; + next[idx] = char; + return next; + }); + setFocusIndex(idx === 5 ? 5 : idx + 1); + if (idx === 5) { + // Finish and carry forward + setTimeout(() => { + onContinue(sampleCode); + }, 600); + } + }, idx * 150); + }); + setShowNotification(false); + }; + + const formattedTime = `00:${timeLeft.toString().padStart(2, '0')}`; + const isOtpComplete = digits.every(digit => digit !== ''); + + const handleManualVerify = () => { + if (isOtpComplete) { + onContinue(digits); + } else { + // Just bypass for smoother testing with default OTP + onContinue(['5', '5', '5', '5', '5', '5']); + } + }; + + const displayMobile = state.mobileNumber + ? `+91 ${state.mobileNumber.slice(0, 5)} ${state.mobileNumber.slice(5)}` + : '+91 98765 43210'; + + return ( +
+ {/* Toast SMS Notification Pop Banner (Simulating Auto-OTP Trigger) */} + {showNotification && ( +
+
+ +
+
+
+ Messages • now + Simulated SMS +
+

PozoApp: Your OTP verification check code matches 943715.

+

+ ⚡ Click to auto-detect & compile code +

+
+
+ )} + + {/* Top App bar */} +
+ + PozoApp + Step 2.5 of 5 +
+ + {/* Progress sliding bar with interactive 2.5/5 index state */} +
+
+
+
+
+
+
+
+
+ + {/* Core View panel */} +
+ {/* Verification pulse badge illustration */} +
+
+
+ sms +
+ {/* Pulsing rings */} +
+
+ +

Verifying your number

+

+ We've sent a 6-digit code to {displayMobile} + +

+
+ + {/* OTP Input block */} +
+
+ {digits.map((digit, index) => ( +
{ + setFocusIndex(index); + inputRefs.current[index]?.focus(); + }} + className={`w-11 sm:w-12 h-14 bg-white border-b-2 ${ + digit + ? 'border-primary' + : focusIndex === index + ? 'border-primary shadow-sm bg-primary/5' + : 'border-outline-variant' + } flex items-center justify-center rounded-t-lg transition-all duration-200 cursor-pointer shadow-sm relative`} + > + {digit ? ( + {digit} + ) : focusIndex === index ? ( +
+ ) : null} + + {/* Secret focus handler inputs */} + { if (el) inputRefs.current[index] = el; }} + type="text" + maxLength={1} + pattern="[0-9]*" + inputMode="numeric" + value={digit} + onChange={(e) => handleDigitChange(index, e.target.value)} + onKeyDown={(e) => handleKeyDown(index, e)} + onFocus={() => setFocusIndex(index)} + className="absolute inset-0 opacity-0 cursor-pointer w-full h-full" + /> +
+ ))} +
+ + {/* Loading loader alert box */} +
+
+
+
+
+
+ Auto-detecting OTP... +
+ + {/* Interactive actions row */} +
+
+ + + {timeLeft > 0 ? ( + <>Resend code in {formattedTime} + ) : ( + + )} + +
+ + {/* WhatsApp CTA */} + +
+
+
+ + {/* Modern navigation dock with primary verifying triggers */} +
+ + + + + {/* The Action triggering forward */} + +
+
+ ); +} diff --git a/src/components/SetupCompleteScreen.tsx b/src/components/SetupCompleteScreen.tsx new file mode 100644 index 0000000..cb659df --- /dev/null +++ b/src/components/SetupCompleteScreen.tsx @@ -0,0 +1,167 @@ +import React, { useEffect, useState } from 'react'; +import { Check, Store, Receipt, Sparkles } from 'lucide-react'; +import { OnboardingState, BUSINESS_TYPES } from '../types'; + +interface SetupCompleteProps { + onContinue: () => void; + state: OnboardingState; +} + +interface ConfettiPart { + id: number; + left: string; + size: string; + delay: string; + duration: string; + color: string; + shape: string; +} + +export default function SetupCompleteScreen({ onContinue, state }: SetupCompleteProps) { + const [confetti, setConfetti] = useState([]); + + useEffect(() => { + // Generate simulated paper confetti arrays on mount + const colors = ['#af101a', '#54a0fe', '#298030', '#ffb3ac', '#ffdad6', '#a5c8ff', '#82db7e']; + const shapes = ['circle', 'square', 'triangle']; + const items = Array.from({ length: 45 }).map((_, i) => ({ + id: i, + left: `${Math.random() * 100}vw`, + size: `${Math.random() * 8 + 6}px`, + delay: `${Math.random() * 3}s`, + duration: `${Math.random() * 2.5 + 2.5}s`, + color: colors[Math.floor(Math.random() * colors.length)], + shape: shapes[Math.floor(Math.random() * shapes.length)] + })); + setConfetti(items); + }, []); + + const getBusinessTypeName = (typeId: string) => { + const matched = BUSINESS_TYPES.find(b => b.id === typeId); + if (matched) return matched.name; + return 'Retail / Grocery'; + }; + + const businessTitle = state.businessName || 'Sharma General Store'; + const typeDisplay = state.businessType ? getBusinessTypeName(state.businessType) : 'Retail / Grocery'; + + return ( +
+ {/* Dynamic Cascading Confetti Layers */} +
+ {confetti.map((c) => ( +
+ ))} +
+ + {/* Embedded falling animation style injection */} + + + {/* Top micro progress indicator (Completely active 100% completed) */} +
+ +
+ Step 5 of 5 Completed + + + Onboarding Done + +
+ + {/* Main Stream centered scroll wrapper */} +
+ {/* Rounded double rings success check icon bubble */} +
+
+ +
+ {/* Echo ping ring */} +
+
+ + {/* Celebrating message */} +
+

+ Setup Complete! 🎉 +

+

+ Your billing dashboard is ready for action. +

+
+ + {/* Dynamic Glassmorphic Recap Card */} +
+ {/* Section Row 1: Business name */} +
+
+ +
+
+

Business Name

+

{businessTitle}

+
+
+ + {/* Dividing border */} +
+ + {/* Section Row 2: Category */} +
+
+ category +
+
+

Business Type

+

{typeDisplay}

+
+
+
+
+ + {/* Pinned Bottom final launcher button */} +
+
+ +
+
+
+ ); +} diff --git a/src/components/WelcomeScreen.tsx b/src/components/WelcomeScreen.tsx new file mode 100644 index 0000000..de82fc6 --- /dev/null +++ b/src/components/WelcomeScreen.tsx @@ -0,0 +1,130 @@ +import React from 'react'; +import { ArrowRight, Check, BadgeCheck, FileText, Wallet, Percent, TrendingUp } from 'lucide-react'; +import { OnboardingState } from '../types'; + +interface WelcomeScreenProps { + onContinue: () => void; + state: OnboardingState; +} + +export default function WelcomeScreen({ onContinue }: WelcomeScreenProps) { + return ( +
+ {/* Top micro progress indicator */} +
+
+
+
+
+
+
+ + {/* Main Core View Area (Scrollable to ensure fit) */} +
+ {/* Brand Logo Header */} +
+
+ Pozo +
+ IN +
+
+
+ + {/* Headline & Value Proposition */} +
+

+ Manage your business billing in 3 clicks! +

+

+ The fastest, most reliable tool for Indian MSMEs to run their shop. +

+ +
+ + + Trusted by 10,000+ merchants + +
+
+ + {/* Abstract Bento Dashboard Mockup representation */} +
+ {/* Simulated dashboard container */} +
+ {/* Header profile row */} +
+
+
+
+
+
+
+ + {/* Action streams inside dashboard model */} +
+ {/* Item row 1: Bill item */} +
+
+ +
+
+
+
+
+ +
+ + {/* Item row 2: Stocks alerts */} +
+
+ +
+
+
+
+
+ +
+
+
+ + {/* Floating UI Elements matching Screen 1 overlay cards */} + {/* 1. Green "Saved" checked state card right shadow */} +
+
+ +
+ Saved +
+ + {/* 2. Red billing currency tag floating lower left */} +
+ ₹ 4,500 +
+
+
+ + {/* Pinned Bottom Primary Action Zone */} +
+
+ + + {/* Dynamic Pagination slider dots */} +
+
+
+
+
+
+
+
+ ); +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..b3dfaea --- /dev/null +++ b/src/index.css @@ -0,0 +1,107 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@500;600;700;800&display=swap'); +@import "tailwindcss"; + +@theme { + --font-sans: "Inter", ui-sans-serif, system-ui; + --font-display: "Plus Jakarta Sans", "Inter", sans-serif; + + /* Custom Color Palette from the design tokens */ + --color-inverse-on-surface: #f1f1f1; + --color-on-primary-fixed: #410003; + --color-tertiary: #016619; + --color-surface-tint: #ba1a20; + --color-on-secondary-fixed-variant: #004786; + --color-on-primary-container: #fff2f0; + --color-surface-container-lowest: #ffffff; + --color-on-tertiary: #ffffff; + --color-surface-dim: #dadada; + --color-surface-container: #eeeeee; + --color-on-primary: #ffffff; + --color-tertiary-fixed: #9df898; + --color-secondary-fixed-dim: #a5c8ff; + --color-inverse-surface: #2f3131; + --color-inverse-primary: #ffb3ac; + --color-on-background: #1a1c1c; + --color-primary-container: #d32f2f; + --color-on-tertiary-fixed: #002204; + --color-error: #ba1a1a; + --color-surface-bright: #f9f9f9; + --color-on-surface: #1a1c1c; + --color-on-primary-fixed-variant: #930010; + --color-tertiary-fixed-dim: #82db7e; + --color-secondary: #005faf; + --color-on-secondary: #ffffff; + --color-on-secondary-fixed: #001c3a; + --color-primary-fixed-dim: #ffb3ac; + --color-on-tertiary-fixed-variant: #005312; + --color-surface-variant: #e2e2e2; + --color-on-error-container: #93000a; + --color-background: #f9f9f9; + --color-on-secondary-container: #003567; + --color-secondary-container: #54a0fe; + --color-outline-variant: #e4beba; + --color-secondary-fixed: #d4e3ff; + --color-primary: #af101a; + --color-brand-red: #af101a; + --color-brand-red-dark: #86000d; + --color-surface-container-low: #f3f3f3; + --color-on-tertiary-container: #daffd1; + --color-surface: #f9f9f9; + --color-error-container: #ffdad6; + --color-primary-fixed: #ffdad6; + --color-on-surface-variant: #5b403d; + --color-tertiary-container: #298030; + --color-on-error: #ffffff; + --color-surface-container-high: #e8e8e8; + --color-surface-container-highest: #e2e2e2; + --color-outline: #8f6f6c; +} + +/* Base custom classes for high fidelity details */ +.bg-pattern { + background-image: radial-gradient(#e4beba 0.8px, transparent 0.8px); + background-size: 20px 20px; +} + +.bg-pattern-fine { + background-image: radial-gradient(#e2e2e2 1px, transparent 1px); + background-size: 15px 15px; +} + +@keyframes popIn { + 0% { transform: scale(0); opacity: 0; } + 100% { transform: scale(1); opacity: 1; } +} + +@keyframes fadeInUp { + 0% { transform: translateY(15px); opacity: 0; } + 100% { transform: translateY(0); opacity: 1; } +} + +@keyframes slideLeft { + 0% { transform: translateX(20px); opacity: 0; } + 100% { transform: translateX(0); opacity: 1; } +} + +.animate-pop-in { + animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; +} + +.animate-fade-in-up { + opacity: 0; + animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards; +} + +.animate-slide-left { + opacity: 0; + animation: slideLeft 0.35s cubic-bezier(0.16, 1, 0.3, 1) forwards; +} + +/* Custom Hide Scrollbar */ +.no-scrollbar::-webkit-scrollbar { + display: none; +} +.no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..080dac3 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import {StrictMode} from 'react'; +import {createRoot} from 'react-dom/client'; +import App from './App.tsx'; +import './index.css'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..cf343a0 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,32 @@ +export type OnboardingStep = + | 'welcome' + | 'mobile-login' + | 'otp-verification' + | 'business-setup' + | 'customize-setup' + | 'setup-complete'; + +export interface BusinessFeatures { + barcodeScanner: boolean; + kotManagement: boolean; + inventoryAlerts: boolean; +} + +export interface OnboardingState { + step: OnboardingStep; + mobileNumber: string; + otpCode: string[]; + businessName: string; + businessType: string; + gstin: string; + features: BusinessFeatures; +} + +export const BUSINESS_TYPES = [ + { id: 'supermarket', name: 'Supermarket', icon: 'shopping_cart' }, + { id: 'restaurant', name: 'Restaurant', icon: 'restaurant' }, + { id: 'clothing', name: 'Clothing', icon: 'checkroom' }, + { id: 'kirana', name: 'Kirana', icon: 'local_mall' }, + { id: 'grocers', name: 'Grocers', icon: 'storefront' }, + { id: 'others', name: 'Others', icon: 'grid_view' } +] as const; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d88f175 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2022", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "ESNext", + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "skipLibCheck": true, + "moduleResolution": "bundler", + "isolatedModules": true, + "moduleDetection": "force", + "allowJs": true, + "jsx": "react-jsx", + "paths": { + "@/*": [ + "./*" + ] + }, + "allowImportingTsExtensions": true, + "noEmit": true + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..fc23e76 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,22 @@ +import tailwindcss from '@tailwindcss/vite'; +import react from '@vitejs/plugin-react'; +import path from 'path'; +import {defineConfig} from 'vite'; + +export default defineConfig(() => { + return { + plugins: [react(), tailwindcss()], + resolve: { + alias: { + '@': path.resolve(__dirname, '.'), + }, + }, + server: { + // HMR is disabled in AI Studio via DISABLE_HMR env var. + // Do not modify—file watching is disabled to prevent flickering during agent edits. + hmr: process.env.DISABLE_HMR !== 'true', + // Disable file watching when DISABLE_HMR is true to save CPU during agent edits. + watch: process.env.DISABLE_HMR === 'true' ? null : {}, + }, + }; +});