Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b279212a95 | |||
| ed1a9d70fb | |||
| 4f11e7bb00 | |||
|
|
2f9118085c | ||
|
|
c620aa71cc | ||
|
|
63244606be | ||
|
|
3b350dbefb | ||
|
|
6deab507d8 | ||
|
|
a2698557ea | ||
|
|
fedd76fc67 | ||
|
|
456f313056 | ||
|
|
f67f486838 | ||
|
|
688ce6bec8 | ||
|
|
05a7aedf54 | ||
|
|
adc32e730d | ||
|
|
f25a5c7a18 | ||
|
|
54f7689e40 | ||
|
|
ce9216ad94 | ||
|
|
da2301a2af | ||
|
|
004c146967 | ||
|
|
c980407287 | ||
|
|
95c9697830 | ||
|
|
a50cad6daa | ||
|
|
7e43b678ea | ||
|
|
8499fa8b07 | ||
|
|
683f67877e | ||
|
|
31bb82d49b | ||
|
|
6dd9b73f9a | ||
|
|
f94a3e2fb5 | ||
|
|
b1847ff8f5 | ||
|
|
234d0d3c7b | ||
|
|
2383cd9e1d | ||
|
|
1703fefd20 | ||
|
|
0ef172887c | ||
|
|
5608484991 | ||
|
|
94b989ad9d | ||
|
|
6670a50ad4 | ||
|
|
0276e8c217 | ||
|
|
4d88cd08c7 | ||
|
|
6cbf864cc9 | ||
|
|
f6d337fbfe | ||
|
|
0132c76569 | ||
|
|
29ab5a9eac | ||
|
|
2b016a0bb0 | ||
|
|
b4990cbe21 | ||
|
|
99db86f10c | ||
|
|
7f88f152aa | ||
|
|
faa62bb9ad | ||
|
|
1e108c6c89 | ||
|
|
ab2a195032 | ||
|
|
ba5ddc1fa9 | ||
|
|
c3420bb9bc | ||
|
|
7a77a0cb16 | ||
|
|
b2abd22753 | ||
|
|
f5d22921b9 | ||
|
|
e40b36a181 | ||
|
|
9b187684b5 |
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -1,21 +1,25 @@
|
||||
# *<! ------ App ------!>*
|
||||
|
||||
APP_NAME="MyApp"
|
||||
APP_NAME="Raster"
|
||||
APP_ENV="local"
|
||||
APP_DEBUG="true"
|
||||
APP_URL="https://mywoocommercestore.com"
|
||||
APP_URL="https://rasterdoo.com"
|
||||
|
||||
ASSET_PATH_PUBLIC="public/assets/"
|
||||
ASSET_PATH_IMAGES="public/assets/images"
|
||||
TIMEZONE="UTC"
|
||||
|
||||
LIGHT_THEME_ID="default_light_theme"
|
||||
DARK_THEME_ID="default_dark_theme"
|
||||
|
||||
# *<! ------ Language ------!>*
|
||||
|
||||
DEFAULT_LOCALE=null
|
||||
DEFAULT_LOCALE="en"
|
||||
# supports: "en" (English), "es" (Spanish), "fr" (French), "hi" (Hindi), "it" (Italian), "pt" (Portuguese) or "zh" (Simplified Chinese)
|
||||
|
||||
# *<! ------ WooSignal Config ------!>*
|
||||
|
||||
APP_KEY="your app key"
|
||||
APP_KEY="app_50818d11780aaba6b545076dea5b90"
|
||||
# App key from WooSignal link: https://woosignal.com/dashboard
|
||||
|
||||
# *<! ------ STRIPE (OPTIONAL) ------!>*
|
||||
@ -38,7 +42,17 @@ PAYPAL_LIVE_MODE=null
|
||||
PAYPAL_LOCALE=null
|
||||
# Use BCP-47 code from this link https://developer.paypal.com/docs/api/reference/locale-codes/
|
||||
|
||||
# *<! ------ RAZORPAY (OPTIONAL) ------!>*
|
||||
|
||||
RAZORPAY_API_KEY=""
|
||||
|
||||
# *<! ------ EXTRAS ------!>*
|
||||
|
||||
PRODUCT_PLACEHOLDER_IMAGE="https://woosignal.com/images/woocommerce-placeholder.png"
|
||||
# Sets the default placeholder image for products with no image
|
||||
|
||||
AUTH_USER_KEY="AUTH_USER"
|
||||
FCM_ENABLED=null
|
||||
|
||||
ENCRYPT_KEY=null
|
||||
ENCRYPT_SECRET=null
|
||||
@ -1,3 +1,124 @@
|
||||
## [6.10.1] - 2023-08-28
|
||||
|
||||
* Refactor project for Nylo 5.x.
|
||||
* Fix AndroidManifest splash screen
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.10.0] - 2023-08-21
|
||||
|
||||
* Small refactor to project
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.9.0] - 2023-07-13
|
||||
|
||||
* Pull firebase config via woosignal api
|
||||
* New encrypt key and secret added to .env
|
||||
* fix fetchRelated to return "publish" products
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.8.2] - 2023-07-04
|
||||
|
||||
* Update gradle + kotlin versions.
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.8.1] - 2023-07-03
|
||||
|
||||
* Fix auth bug.
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.8.0] - 2023-07-03
|
||||
|
||||
* UI fixes.
|
||||
* Fix price on coupon page error alerts.
|
||||
* Fix issue where IOS builds were not using the correct build version.
|
||||
* Small refactor to the project.
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.7.0] - 2023-06-20
|
||||
|
||||
* Refactor project for Nylo 5.x.
|
||||
* New Firebase provider for FCM.
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.6.2] - 2023-06-14
|
||||
|
||||
* Page bug fixes
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.6.1] - 2023-05-28
|
||||
|
||||
* Refactor widgets + bug fixes
|
||||
* Refactor extensions.dart
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.6.0] - 2023-05-18
|
||||
|
||||
* Nylo v5.0.0 migration
|
||||
* Refactor project
|
||||
* Flutter v3.10.0 compatibility
|
||||
|
||||
## [6.5.1] - 2023-03-04
|
||||
|
||||
* New translation added.
|
||||
|
||||
## [6.5.0] - 2023-03-04
|
||||
|
||||
* When making payments via Stripe, it will now save the card for later.
|
||||
* Small UI changes to the checkout confirmation page.
|
||||
* New translation added.
|
||||
* Pubspec.yaml dependency updates.
|
||||
|
||||
## [6.4.1] - 2023-02-23
|
||||
|
||||
* Upgrade to Nylo v4.1.3
|
||||
* Small refactor to TextStyle
|
||||
* Fix the ThemeColor.get helper method to support ColorStyles.
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.4.0] - 2023-01-06
|
||||
|
||||
* Upgrade to Nylo v4.0.0
|
||||
* Update copyright
|
||||
* Refactor wp_json_api metadata
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.3.1] - 2022-11-04
|
||||
|
||||
* Fix email address bug in customer_address_input.dart
|
||||
|
||||
## [6.3.0] - 2022-11-03
|
||||
|
||||
* Ability to add Menu Links to the drawer widget through the WooSignal dashboard
|
||||
* Fix wording when a shipping zone cannot be found to "Shipping is not supported for your location, sorry"
|
||||
* Update account shipping widget to be uniform with the checkout shipping widget
|
||||
* When logged in, the `CheckoutDetailsPage` will now populate shipping info from the users account
|
||||
* Small refactor to resources/pages
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.2.0] - 2022-09-23
|
||||
|
||||
* Migration to use Nylo v3.4.0
|
||||
* Pubspec.yaml dependency updates
|
||||
* Increase the minimum targetSdkVersion to 31
|
||||
* Merge #51, #50, #47, #40, #39 and #38 by @jeanmatthieud
|
||||
* UI changes to the search page for a nicer experience
|
||||
* More translations added throughout the app
|
||||
|
||||
## [6.1.0] - 2022-07-09
|
||||
|
||||
* Add RazorPay
|
||||
* Null safety tweaks to widgets
|
||||
* Ability for users to delete their accounts using WP_JSON
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.0.0] - 2022-05-19
|
||||
|
||||
* Migrate to Nylo 3.x
|
||||
* Null safety
|
||||
* Min dart version 2.17
|
||||
* Refactor product detail screen
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [5.8.0] - 2022-03-29
|
||||
|
||||
* Add phone number to customer input form
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2022, WooSignal Ltd
|
||||
Copyright (c) 2023, WooSignal Ltd
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -4,8 +4,7 @@
|
||||
|
||||
# WooCommerce App: Label StoreMax
|
||||
|
||||
### Label StoreMax - v5.8.0
|
||||
|
||||
### Label StoreMax
|
||||
|
||||
[Official WooSignal WooCommerce App](https://woosignal.com)
|
||||
|
||||
@ -44,7 +43,7 @@ Full documentation this available [here](https://woosignal.com/docs/app/label-st
|
||||
- Browse products, make orders, customer login (via WordPress)
|
||||
- Change app name, logo, customize default language, currency + more
|
||||
- Light and dark mode
|
||||
- Stripe, Cash On Delivery, PayPal
|
||||
- Stripe, Cash On Delivery, PayPal, RazorPay
|
||||
- Localized for en, es, pt, it, hi, fr, zh, tr, nl, de
|
||||
- Orders show as normal in WooCommerce
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ android {
|
||||
exclude 'META-INF/DEPENDENCIES'
|
||||
}
|
||||
|
||||
compileSdkVersion 31
|
||||
compileSdkVersion 33
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
@ -44,7 +44,7 @@ android {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId "com.woosignal.android"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 33
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
multiDexEnabled true
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<application
|
||||
android:name="${applicationName}"
|
||||
android:label="Label StoreMax"
|
||||
android:label="Raster Knjizara"
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
@ -21,7 +21,8 @@
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:screenOrientation="portrait"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
@ -30,15 +31,7 @@
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<!-- Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
gap between the end of Android's launch screen and the painting of
|
||||
Flutter's first frame. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background"
|
||||
/>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 12 KiB |
@ -1,12 +1,12 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.1'
|
||||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,6 @@ subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
||||
|
||||
@ -21,6 +21,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>9.0</string>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
49
LabelStoreMax/ios/Podfile
Normal file
@ -0,0 +1,49 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '11.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
|
||||
installer.generated_projects.each do |project|
|
||||
project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -155,7 +155,7 @@
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
LastUpgradeCheck = 1430;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
97C146ED1CF9000F007C117D = {
|
||||
@ -199,10 +199,12 @@
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
@ -213,6 +215,7 @@
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
@ -370,6 +373,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -508,6 +512,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -540,6 +545,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
LastUpgradeVersion = "1430"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
@ -15,13 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>You can take photos of your payment details.</string>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>13.0</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
@ -36,14 +34,20 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>13.0</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>You can take photos of your payment details.</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "Der Versand wird für Ihr Land leider nicht unterstützt",
|
||||
"Search": "Suche",
|
||||
"Debit or Credit Card": "Debit- oder Kreditkarte",
|
||||
"Cash on delivery": "Barzahlung bei Lieferung",
|
||||
"Oops, something went wrong": "Ups! Irgendwas lief schief",
|
||||
"Tax": "MwSt",
|
||||
"No results": "Keine Ergebnisse",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "Hinterlassen Sie eine Bewertung",
|
||||
"How would you rate": "Wie beurteilen Sie",
|
||||
"Submit": "einreichen",
|
||||
"Your review has been submitted": "Ihre Bewertung wurde übermittelt"
|
||||
"Your review has been submitted": "Ihre Bewertung wurde übermittelt",
|
||||
"Delete Account": "Konto löschen",
|
||||
"Phone Number": "Telefonnummer",
|
||||
"Delete your account": "Lösche deinen Account",
|
||||
"Are you sure?": "Bist du dir sicher?",
|
||||
"Yes, delete my account": "Ja, lösche mein Konto",
|
||||
"Account deleted": "Konto gelöscht",
|
||||
"Shipping is not supported for your location, sorry": "Der Versand wird für Ihren Standort nicht unterstützt, tut mir leid",
|
||||
"Order Summary": "Bestellübersicht",
|
||||
"By completing this order, I agree to all": "Mit Abschluss dieser Bestellung stimme ich allem zu"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "Shipping is not supported for your country, sorry",
|
||||
"Search": "Search",
|
||||
"Debit or Credit Card": "Debit or Credit Card",
|
||||
"Cash on delivery": "Cash on delivery",
|
||||
"Oops, something went wrong": "Oops, something went wrong",
|
||||
"Tax": "Tax",
|
||||
"No results": "No results",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "Leave a review",
|
||||
"How would you rate": "How would you rate",
|
||||
"Submit": "Submit",
|
||||
"Your review has been submitted": "Your review has been submitted"
|
||||
"Your review has been submitted": "Your review has been submitted",
|
||||
"Delete Account": "Delete Account",
|
||||
"Phone Number": "Phone Number",
|
||||
"Delete your account": "Delete your account",
|
||||
"Are you sure?": "Are you sure?",
|
||||
"Yes, delete my account": "Yes, delete my account",
|
||||
"Account deleted": "Account deleted",
|
||||
"Shipping is not supported for your location, sorry": "Shipping is not supported for your location, sorry",
|
||||
"Order Summary": "Order Summary",
|
||||
"By completing this order, I agree to all": "By completing this order, I agree to all"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "El envío no es compatible con su país, lo siento",
|
||||
"Search": "Buscar",
|
||||
"Debit or Credit Card": "Tarjeta de débito o crédito",
|
||||
"Cash on delivery": "Contra reembolso",
|
||||
"Oops, something went wrong": "Huy! Algo salió mal",
|
||||
"Tax": "Impuesto",
|
||||
"No results": "No hay resultados",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "Dejar un comentario",
|
||||
"How would you rate": "Cómo calificarías",
|
||||
"Submit": "Entregar",
|
||||
"Your review has been submitted": "Tu reseña ha sido enviada"
|
||||
"Your review has been submitted": "Tu reseña ha sido enviada",
|
||||
"Delete Account": "Borrar cuenta",
|
||||
"Phone Number": "Número de teléfono",
|
||||
"Delete your account": "eliminar su cuenta",
|
||||
"Are you sure?": "¿Está seguro?",
|
||||
"Yes, delete my account": "Sí, eliminar mi cuenta",
|
||||
"Account deleted": "Cuenta borrada",
|
||||
"Shipping is not supported for your location, sorry": "El envío no es compatible para su ubicación, lo siento",
|
||||
"Order Summary": "Resumen del pedido",
|
||||
"By completing this order, I agree to all": "Al completar este pedido, acepto todos"
|
||||
}
|
||||
@ -1,19 +1,19 @@
|
||||
{
|
||||
"Categories": "Les catégories",
|
||||
"Categories": "Catégories",
|
||||
"Shop": "Boutique",
|
||||
"Newest": "Le plus récent",
|
||||
"Browse categories": "Parcourir les catégories",
|
||||
"Cart": "Chariot",
|
||||
"You need items in your cart to checkout": "Vous avez besoin d'articles dans votre panier pour passer à la caisse",
|
||||
"Cart": "Panier",
|
||||
"You need items in your cart to checkout": "Ajoutez d'abord des articles à votre panier !",
|
||||
"Updated": "Mise à jour",
|
||||
"Item removed": "Élément supprimé",
|
||||
"Success": "Succès",
|
||||
"Cart cleared": "Panier effacé",
|
||||
"Success": "C'est fait !",
|
||||
"Cart cleared": "Panier vidé",
|
||||
"Shopping Cart": "Panier",
|
||||
"Clear Cart": "Vider le panier",
|
||||
"Empty Basket": "Panier vide",
|
||||
"PROCEED TO CHECKOUT": "PASSER À LA CAISSE",
|
||||
"Browse": "Feuilleter",
|
||||
"PROCEED TO CHECKOUT": "PASSER AU PAIEMENT",
|
||||
"Browse": "Parcourir",
|
||||
"Search results for": "Résultats de recherche pour",
|
||||
"Select a": "Sélectionner un",
|
||||
"Added to cart": "Ajouté au panier",
|
||||
@ -22,53 +22,53 @@
|
||||
"Choose your options": "Choisissez vos options",
|
||||
"Out of stock": "En rupture de stock",
|
||||
"In Stock": "En stock",
|
||||
"Add to cart": "Ajouter au chariot",
|
||||
"Oops": "Oops",
|
||||
"Add to cart": "Ajouter au panier",
|
||||
"Oops": "Oups",
|
||||
"Please select valid options first": "Veuillez d'abord sélectionner les options valides",
|
||||
"Sorry": "Désolé",
|
||||
"This item is not in stock": "Cet article n'est pas en réserve",
|
||||
"Description": "La description",
|
||||
"This item is not in stock": "Cet article n'est pas en stock",
|
||||
"Description": "Description",
|
||||
"Full description": "Description complète",
|
||||
"ADD TO CART": "AJOUTER AU CHARIOT",
|
||||
"ADD TO CART": "AJOUTER AU PANIER",
|
||||
"This item is out of stock": "L'article n'est plus en stock",
|
||||
"Add your shipping details first": "Ajoutez d'abord vos détails d'expédition",
|
||||
"Checkout": "Check-out",
|
||||
"Add your shipping details first": "Ajoutez d'abord vos informations d'expédition",
|
||||
"Checkout": "Commander",
|
||||
"Billing/shipping details": "Détails de facturation / expédition",
|
||||
"Add billing & shipping details": "Ajouter les détails de facturation et d'expédition",
|
||||
"Payment method": "Mode de paiement",
|
||||
"Pay with": "Payer avec",
|
||||
"Select a payment method": "Choisissez une méthode de paiement",
|
||||
"Shipping selected": "Livraison sélectionnée",
|
||||
"Select shipping": "Sélectionnez Livraison",
|
||||
"Select shipping": "Sélectionnez le mode de livraison",
|
||||
"Select a shipping option": "Sélectionnez une option d'expédition",
|
||||
"Shipping fee": "Frais d'expédition",
|
||||
"Subtotal": "Total",
|
||||
"Total": "Total",
|
||||
"CHECKOUT": "CHECK-OUT",
|
||||
"One moment": "Un moment",
|
||||
"CHECKOUT": "COMMANDER",
|
||||
"One moment": "Veuillez patienter",
|
||||
"Please select add your billing/shipping address to proceed": "Veuillez sélectionner ajouter votre adresse de facturation / expédition pour continuer",
|
||||
"Your billing/shipping details are incomplete": "Vos coordonnées de facturation / expédition sont incomplètes",
|
||||
"Please select a shipping method to proceed": "Veuillez sélectionner une méthode d'expédition pour continuer",
|
||||
"Please select a payment method to proceed": "Veuillez sélectionner un mode de paiement pour continuer",
|
||||
"Something went wrong, please contact our store": "Quelque chose s'est mal passé, veuillez contacter notre magasin",
|
||||
"Something went wrong, please contact our store": "Quelque chose s'est mal passé, veuillez contacter notre équipe",
|
||||
"Error": "Erreur",
|
||||
"Order Status": "Statut de la commande",
|
||||
"Thank You!": "Merci!",
|
||||
"Thank You!": "Merci !",
|
||||
"Your transaction details": "Vos détails de transaction",
|
||||
"Order Ref": "Réf commande",
|
||||
"Items": "Articles",
|
||||
"Back to Home": "De retour à la maison",
|
||||
"Orders": "Ordres",
|
||||
"Back to Home": "Retourner à l'accueil",
|
||||
"Orders": "Commandes",
|
||||
"Billing & Shipping Details": "Détails de facturation et d'expédition",
|
||||
"First Name": "Prénom",
|
||||
"Last Name": "Nom de famille",
|
||||
"Address Line": "Ligne d'adresse",
|
||||
"Address Line": "Adresse",
|
||||
"City": "Ville",
|
||||
"Postal code": "Code postal",
|
||||
"Email address": "Adresse électronique",
|
||||
"Selected": "Choisi",
|
||||
"Selected": "Sélectionné",
|
||||
"Select country": "Choisissez le pays",
|
||||
"Remember my details": "Rappelez-vous mes coordonnées",
|
||||
"Remember my details": "Retenir mes coordonnées",
|
||||
"USE SHIPPING ADDRESS": "UTILISER L'ADRESSE D'EXPÉDITION",
|
||||
"About": "À propos de",
|
||||
"Privacy policy": "Politique de confidentialité",
|
||||
@ -76,12 +76,13 @@
|
||||
"Version": "Version",
|
||||
"Payment Method": "Mode de paiement",
|
||||
"CANCEL": "ANNULER",
|
||||
"Shipping Methods": "méthodes de livraison",
|
||||
"Shipping Methods": "Méthodes de livraison",
|
||||
"Shipping is not supported for your country, sorry": "La livraison n'est pas prise en charge pour votre pays, désolé",
|
||||
"Search": "Chercher",
|
||||
"Debit or Credit Card": "Carte de débit ou de crédit",
|
||||
"Cash on delivery": "Paiement à la livraison",
|
||||
"Oops, something went wrong": "Oups, quelque chose s'est mal passé",
|
||||
"Tax": "Impôt",
|
||||
"Tax": "TVA",
|
||||
"No results": "Aucun résultat",
|
||||
"There is an item out of stock": "Il y a un article en rupture de stock",
|
||||
"Maximum stock reached": "Stock maximum atteint",
|
||||
@ -98,35 +99,35 @@
|
||||
"Create an account": "Créer un compte",
|
||||
"Login": "S'identifier",
|
||||
"Password": "Mot de passe",
|
||||
"Oops!": "Oops!",
|
||||
"Oops!": "Oups !",
|
||||
"Invalid login credentials": "Authentification invalide",
|
||||
"That email address is not valid": "Cette adresse e-mail n'est pas valide",
|
||||
"Password must be a min 6 characters": "Le mot de passe doit contenir au moins 6 caractères",
|
||||
"Please check your details": "S'il vous plaît vérifier vos informations",
|
||||
"Please check your details": "Veuillez vérifier vos informations",
|
||||
"Invalid": "Invalide",
|
||||
"Actions": "Actions",
|
||||
"View Terms and Conditions or Privacy policy": "Afficher les conditions générales ou la politique de confidentialité",
|
||||
"Terms and Conditions": "Termes et conditions",
|
||||
"Terms and Conditions": "Mentions légales",
|
||||
"Privacy Policy": "Politique de confidentialité",
|
||||
"terms and conditions": "Termes et conditions",
|
||||
"terms and conditions": "mentions légales",
|
||||
"and": "et",
|
||||
"By tapping \"Register\" you agree to ": "En appuyant sur \"S'inscrire\", vous acceptez de ",
|
||||
"privacy policy": "politique de confidentialité",
|
||||
"Sign up": "S'inscrire",
|
||||
"Email": "Email",
|
||||
"Update details": "Mettre à jour les détails",
|
||||
"Settings": "Réglages",
|
||||
"Update details": "Informations personnelles",
|
||||
"Settings": "Paramètres",
|
||||
"Account": "Compte",
|
||||
"Logout": "Se déconnecter",
|
||||
"No orders found": "Aucune commande trouvée",
|
||||
"items": "articles",
|
||||
"Update Details": "Détails de mise à jour",
|
||||
"Invalid details": "Détails invalides",
|
||||
"Update Details": "Mettre à jour les informations",
|
||||
"Invalid details": "Informations invalides",
|
||||
"Please check your email and password": "Veuillez vérifier votre e-mail et votre mot de passe",
|
||||
"Something went wrong, please try again.": "Une erreur s'est produite. Veuillez réessayer.",
|
||||
"Done": "Terminé",
|
||||
"Billing Details": "Détails de la facturation",
|
||||
"Shipping Details": "Les détails d'expédition",
|
||||
"Billing Details": "Facturation",
|
||||
"Shipping Details": "Expédition",
|
||||
"Shipping Address": "Adresse de livraison",
|
||||
"State": "Etat",
|
||||
"Country": "Pays",
|
||||
@ -143,14 +144,14 @@
|
||||
"Sort results": "Trier les résultats",
|
||||
"you're now logged in": "Vous êtes maintenant connecté",
|
||||
"Hello": "Bonjour",
|
||||
"Welcome back": "Nous saluons le retour",
|
||||
"Welcome back": "Content de vous revoir",
|
||||
"Quantity": "Quantité",
|
||||
"Select a state": "Sélectionner un état",
|
||||
"Select state": "Sélectionnez l'état",
|
||||
"Ship to a different address?": "Expédier à une adresse différente?",
|
||||
"USE DETAILS": "DÉTAILS D'UTILISATION",
|
||||
"USE DETAILS": "METTRE À JOUR",
|
||||
"Not supported, try a card payment": "Non pris en charge, essayez un paiement par carte",
|
||||
"Invalid shipping address, please check your shipping details": "Adresse de livraison non valide, veuillez vérifier vos détails de livraison",
|
||||
"Invalid shipping address, please check your shipping details": "Adresse de livraison non valide, veuillez vérifier vos infos de livraison",
|
||||
"Was": "Était",
|
||||
"off": "de",
|
||||
"Maximum quantity reached": "Quantité maximale atteinte",
|
||||
@ -168,14 +169,14 @@
|
||||
"A user already exists": "Un utilisateur existe déjà",
|
||||
"That email is taken, try another": "Cet e-mail est pris, essayez un autre",
|
||||
"The email field is empty": "Le champ e-mail est vide",
|
||||
"No more orders": "Plus de commandes",
|
||||
"No more orders": "Pas plus de commandes",
|
||||
"Account updated": "Compte mis à jour",
|
||||
"Spend a minimum of": "Dépensez un minimum de",
|
||||
"for": "pour",
|
||||
"Buy Product": "Acheter un produit",
|
||||
"Retry": "Recommencez",
|
||||
"Retry later": "Réessayer plus tard",
|
||||
"Light Mode": "Mode lumière",
|
||||
"Light Mode": "Mode clair",
|
||||
"Dark Mode": "Mode sombre",
|
||||
"PayPal Checkout": "Paiement PayPal",
|
||||
"Processing Payment": "Traitement du paiement",
|
||||
@ -183,26 +184,26 @@
|
||||
"If you are not automatically redirected to PayPal within 5 seconds": "Si vous n'etes pas automatiquement redirige vers PayPal dans les 5 secondes",
|
||||
"Payment Cancelled": "Paiement annulé",
|
||||
"The payment has been cancelled": "Le paiement a été annulé",
|
||||
"Must have": "Doit avoir",
|
||||
"Must have": "Produits à voir",
|
||||
"Our selection of new items": "Notre sélection de nouveautés",
|
||||
"Register": "S'inscrire",
|
||||
"No payment methods are available": "Aucun mode de paiement n'est disponible",
|
||||
"Please enter a valid billing email": "Veuillez saisir une adresse e-mail de facturation valide",
|
||||
"Please enter a valid shipping email": "Veuillez saisir un e-mail de livraison valide",
|
||||
"Free postage": "Sans frais de port",
|
||||
"Free postage": "Frais de port offerts",
|
||||
"PROCESSING": "EN TRAITEMENT",
|
||||
"Social": "Social",
|
||||
"Please enter coupon to redeem": "Veuillez entrer le coupon pour l'utiliser",
|
||||
"Coupon": "Coupon",
|
||||
"Please enter coupon to redeem": "Veuillez entrer le code promo pour l'utiliser",
|
||||
"Coupon": "Code promo",
|
||||
"Apply": "Appliquer",
|
||||
"Apply Coupon": "Appliquer Coupon",
|
||||
"Added to checkout": "Ajouté à la caisse",
|
||||
"Redeem Coupon": "Échanger le coupon",
|
||||
"Apply Coupon": "Appliquer code promo",
|
||||
"Added to checkout": "Ajouté au panier",
|
||||
"Redeem Coupon": "Échanger le code promo",
|
||||
"Add coupon code": "Ajouter un code promo",
|
||||
"Coupon not found": "Coupon introuvable",
|
||||
"Sorry, this coupon can not be used with your cart": "Désolé, ce coupon ne peut pas être utilisé avec votre panier",
|
||||
"You cannot redeem this coupon": "Vous ne pouvez pas utiliser ce coupon",
|
||||
"This coupon has expired": "Ce coupon a expiré",
|
||||
"Coupon not found": "Code promo introuvable",
|
||||
"Sorry, this coupon can not be used with your cart": "Désolé, ce code promo ne peut pas être utilisé avec votre panier",
|
||||
"You cannot redeem this coupon": "Vous ne pouvez pas utiliser ce code promo",
|
||||
"This coupon has expired": "Ce code promo a expiré",
|
||||
"Usage limit has been reached": "La limite d'utilisation a été atteinte",
|
||||
"View All": "Voir tout",
|
||||
"Wishlist": "Liste de souhaits",
|
||||
@ -213,11 +214,20 @@
|
||||
"Spend less than maximumAmount to redeem": "Dépensez moins de {{maximumAmount}} de racheter",
|
||||
"Related products": "Produits connexes",
|
||||
"Reviews": "Commentaires",
|
||||
"There are no reviews yet.": "Il n'y a pas encore de critiques.",
|
||||
"There are no reviews yet.": "Il n'y a pas encore de commentaire.",
|
||||
"More": "Suite",
|
||||
"You may also like": "Tu pourrais aussi aimer",
|
||||
"You may also like": "Vous pourriez aussi aimer",
|
||||
"Leave a review": "Laisser un commentaire",
|
||||
"How would you rate": "Comment évalueriez-vous",
|
||||
"Submit": "Soumettre",
|
||||
"Your review has been submitted": "Votre avis a été soumis"
|
||||
"Submit": "Envoyer",
|
||||
"Your review has been submitted": "Votre avis a été soumis",
|
||||
"Delete Account": "Supprimer le compte",
|
||||
"Phone Number": "Numéro de téléphone",
|
||||
"Delete your account": "Supprimer votre compte",
|
||||
"Are you sure?": "Êtes-vous sûr?",
|
||||
"Yes, delete my account": "Oui, supprimer mon compte",
|
||||
"Account deleted": "Compte supprimé",
|
||||
"Shipping is not supported for your location, sorry": "L'expédition n'est pas prise en charge pour votre emplacement, désolé",
|
||||
"Order Summary": "Récapitulatif de la commande",
|
||||
"By completing this order, I agree to all": "En remplissant cette commande, j'accepte toutes"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "shiping aapake desh ke lie samarthit nahin hai, kshama karen",
|
||||
"Search": "khoj",
|
||||
"Debit or Credit Card": "debit ya kredit kaard",
|
||||
"Cash on delivery": "dilavaree par nakadee\n",
|
||||
"Oops, something went wrong": "oh! kuchh galat ho gaya hai",
|
||||
"Tax": "kar",
|
||||
"No results": "koee parinaam nahin",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "sameeksha likhen",
|
||||
"How would you rate": "aap ise kya ret karate hain",
|
||||
"Submit": "prastut karana",
|
||||
"Your review has been submitted": "aapakee sameeksha jama ho chukee hai"
|
||||
"Your review has been submitted": "aapakee sameeksha jama ho chukee hai",
|
||||
"Delete Account": "khaata hata do",
|
||||
"Phone Number": "fon nambar",
|
||||
"Delete your account": "apane khaate ko nasht karo",
|
||||
"Are you sure?": "kya aapako yakeen hai?",
|
||||
"Yes, delete my account": "haan, mera akaunt dileet kar do",
|
||||
"Account deleted": "khaata hataaya gaya",
|
||||
"Shipping is not supported for your location, sorry": "aapake sthaan ke lie shiping samarthit nahin hai, kshama karen",
|
||||
"Order Summary": "aadesh saaraansh",
|
||||
"By completing this order, I agree to all": "is aadesh ko poora karake, main sabhee ke lie sahamat hoon"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "La spedizione non è supportata per il tuo Paese, mi dispiace",
|
||||
"Search": "Ricerca",
|
||||
"Debit or Credit Card": "Bancomat o carta di credito",
|
||||
"Cash on delivery": "Pagamento alla consegna",
|
||||
"Oops, something went wrong": "Oops! Qualcosa è andato storto",
|
||||
"Tax": "Imposta",
|
||||
"No results": "Nessun risultato",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "Lascia una recensione",
|
||||
"How would you rate": "Come valuteresti",
|
||||
"Submit": "Invia",
|
||||
"Your review has been submitted": "La tua recensione è stata inviata"
|
||||
"Your review has been submitted": "La tua recensione è stata inviata",
|
||||
"Delete Account": "Eliminare l'account",
|
||||
"Phone Number": "Numero di telefono",
|
||||
"Delete your account": "cancella il tuo account",
|
||||
"Are you sure?": "Sei sicuro?",
|
||||
"Yes, delete my account": "Sì, elimina il mio account",
|
||||
"Account deleted": "Account cancellato",
|
||||
"Shipping is not supported for your location, sorry": "La spedizione non è supportata per la tua posizione, mi dispiace",
|
||||
"Order Summary": "Riepilogo dell'ordine",
|
||||
"By completing this order, I agree to all": "Completando questo ordine, accetto tutto"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "Verzending wordt niet ondersteund voor uw land, sorry",
|
||||
"Search": "Zoekopdracht",
|
||||
"Debit or Credit Card": "Debet- of creditcard",
|
||||
"Cash on delivery": "Onder rembours",
|
||||
"Oops, something went wrong": "Oeps! Er is iets misgegaan",
|
||||
"Tax": "Belasting",
|
||||
"No results": "Geen resultaten",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "Laat je mening achter",
|
||||
"How would you rate": "Hoe zou jij beoordelen",
|
||||
"Submit": "Indienen",
|
||||
"Your review has been submitted": "Uw beoordeling is verzonden"
|
||||
"Your review has been submitted": "Uw beoordeling is verzonden",
|
||||
"Delete Account": "Account verwijderen",
|
||||
"Phone Number": "Telefoonnummer",
|
||||
"Delete your account": "Verwijder je account",
|
||||
"Are you sure?": "Weet je het zeker?",
|
||||
"Yes, delete my account": "Ja, verwijder mijn account",
|
||||
"Account deleted": "Account verwijderd",
|
||||
"Shipping is not supported for your location, sorry": "Verzending wordt niet ondersteund voor uw locatie, sorry",
|
||||
"Order Summary": "Overzicht van de bestelling",
|
||||
"By completing this order, I agree to all": "Door deze bestelling te voltooien, ga ik akkoord met alles"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "O envio não é suportado pelo seu país, desculpe",
|
||||
"Search": "Procurar",
|
||||
"Debit or Credit Card": "Cartão de Débito ou Crédito",
|
||||
"Cash on delivery": "Dinheiro na entrega",
|
||||
"Oops, something went wrong": "Ops, algo deu errado",
|
||||
"Tax": "Imposto",
|
||||
"No results": "Sem resultados",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "Deixe um comentário",
|
||||
"How would you rate": "Como você avaliaria",
|
||||
"Submit": "Enviar",
|
||||
"Your review has been submitted": "Sua avaliação foi enviada"
|
||||
"Your review has been submitted": "Sua avaliação foi enviada",
|
||||
"Delete Account": "Deletar conta",
|
||||
"Phone Number": "Número de telefone",
|
||||
"Delete your account": "Deletar sua conta",
|
||||
"Are you sure?": "Tem certeza?",
|
||||
"Yes, delete my account": "Sim, excluir minha conta",
|
||||
"Account deleted": "Conta excluída",
|
||||
"Shipping is not supported for your location, sorry": "O envio não é suportado para a sua localização, desculpe",
|
||||
"Order Summary": "Resumo do pedido",
|
||||
"By completing this order, I agree to all": "Ao concluir este pedido, concordo com todos"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "Ülkeniz için gönderim desteklenmiyor, üzgünüm",
|
||||
"Search": "Aramak",
|
||||
"Debit or Credit Card": "Banka veya Kredi Kartı",
|
||||
"Cash on delivery": "Kapıda ödeme",
|
||||
"Oops, something went wrong": "Hoop! Birşeyler yanlış gitti",
|
||||
"Tax": "Vergi",
|
||||
"No results": "Sonuç yok",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "İnceleme bırak",
|
||||
"How would you rate": "Nasıl değerlendirirsiniz",
|
||||
"Submit": "Göndermek",
|
||||
"Your review has been submitted": "İncelemeniz gönderildi"
|
||||
"Your review has been submitted": "İncelemeniz gönderildi",
|
||||
"Delete Account": "Hesabı sil",
|
||||
"Phone Number": "Telefon numarası",
|
||||
"Delete your account": "Hesabını sil",
|
||||
"Are you sure?": "Emin misin?",
|
||||
"Yes, delete my account": "Evet, hesabımı sil",
|
||||
"Account deleted": "Hesap silindi",
|
||||
"Shipping is not supported for your location, sorry": "Bulunduğunuz yer için gönderim desteklenmiyor, üzgünüm",
|
||||
"Order Summary": "Sipariş özeti",
|
||||
"By completing this order, I agree to all": "Bu siparişi tamamlayarak, tümünü kabul ediyorum"
|
||||
}
|
||||
@ -80,6 +80,7 @@
|
||||
"Shipping is not supported for your country, sorry": "您所在的国家/地区不支持运输,抱歉",
|
||||
"Search": "搜索",
|
||||
"Debit or Credit Card": "借记卡或信用卡",
|
||||
"Cash on delivery": "货到付款",
|
||||
"Oops, something went wrong": "哎呀!出事了",
|
||||
"Tax": "税",
|
||||
"No results": "没结果",
|
||||
@ -219,5 +220,14 @@
|
||||
"Leave a review": "发表评论",
|
||||
"How would you rate": "你如何评价",
|
||||
"Submit": "提交",
|
||||
"Your review has been submitted": "您的评论已提交"
|
||||
"Your review has been submitted": "您的评论已提交",
|
||||
"Delete Account": "删除帐户",
|
||||
"Phone Number": "电话号码",
|
||||
"Delete your account": "删除您的帐户",
|
||||
"Are you sure?": "你确定吗?",
|
||||
"Yes, delete my account": "是的,删除我的帐户",
|
||||
"Account deleted": "帐号已删除",
|
||||
"Shipping is not supported for your location, sorry": "您所在的位置不支持送货,抱歉",
|
||||
"Order Summary": "订单摘要",
|
||||
"By completing this order, I agree to all": "通过完成此订单,我同意所有"
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:nylo_support/controllers/controller.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/// Base Controller for the Nylo
|
||||
/// See more on controllers here - https://nylo.dev/docs/2.x/controllers
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
|
||||
import 'package:woosignal/models/response/order.dart';
|
||||
|
||||
@ -17,9 +15,9 @@ class CustomerOrdersLoaderController
|
||||
CustomerOrdersLoaderController();
|
||||
|
||||
Future<void> loadOrders(
|
||||
{@required bool Function(bool hasProducts) hasResults,
|
||||
@required void Function() didFinish,
|
||||
@required String userId}) async {
|
||||
{required bool Function(bool hasProducts) hasResults,
|
||||
required void Function() didFinish,
|
||||
required String userId}) async {
|
||||
await load(
|
||||
hasResults: hasResults,
|
||||
didFinish: didFinish,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -12,10 +12,8 @@ import 'controller.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class LeaveReviewController extends Controller {
|
||||
|
||||
@override
|
||||
construct(BuildContext context) {
|
||||
super.construct(context);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,36 +1,35 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
|
||||
import 'package:woosignal/models/response/product_category.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/product.dart';
|
||||
|
||||
class ProductCategorySearchLoaderController
|
||||
extends WooSignalApiLoaderController<Product> {
|
||||
ProductCategorySearchLoaderController();
|
||||
|
||||
Future<void> loadProducts(
|
||||
{@required bool Function(bool hasProducts) hasResults,
|
||||
@required void Function() didFinish,
|
||||
@required ProductCategory productCategory}) async {
|
||||
{required bool Function(bool hasProducts) hasResults,
|
||||
required void Function() didFinish,
|
||||
required ProductCategory? productCategory}) async {
|
||||
await load(
|
||||
hasResults: hasResults,
|
||||
didFinish: didFinish,
|
||||
apiQuery: (api) => api.getProducts(
|
||||
perPage: 50,
|
||||
category: productCategory.id.toString(),
|
||||
page: page,
|
||||
status: "publish",
|
||||
stockStatus: "instock",
|
||||
),
|
||||
hasResults: hasResults,
|
||||
didFinish: didFinish,
|
||||
apiQuery: (api) => api.getProducts(
|
||||
perPage: 50,
|
||||
category: productCategory!.id.toString(),
|
||||
page: page,
|
||||
status: "publish",
|
||||
stockStatus: "instock",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -14,46 +14,48 @@ import 'package:flutter_app/app/models/cart_line_item.dart';
|
||||
import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/product.dart';
|
||||
import 'package:woosignal/models/response/product_variation.dart'
|
||||
as ws_product_variation;
|
||||
as ws_product_variation;
|
||||
|
||||
import 'controller.dart';
|
||||
|
||||
class ProductDetailController extends Controller {
|
||||
int quantity = 1;
|
||||
Product product;
|
||||
Product? product;
|
||||
|
||||
@override
|
||||
construct(BuildContext context) {
|
||||
super.construct(context);
|
||||
product = data() as Product;
|
||||
product = data() as Product?;
|
||||
}
|
||||
|
||||
viewExternalProduct() {
|
||||
if (product.externalUrl != null && product.externalUrl.isNotEmpty) {
|
||||
openBrowserTab(url: product.externalUrl);
|
||||
if (product!.externalUrl != null && product!.externalUrl!.isNotEmpty) {
|
||||
openBrowserTab(url: product!.externalUrl!);
|
||||
}
|
||||
}
|
||||
|
||||
itemAddToCart({@required CartLineItem cartLineItem, @required Function onSuccess}) async {
|
||||
itemAddToCart(
|
||||
{required CartLineItem cartLineItem, required Function onSuccess}) async {
|
||||
await Cart.getInstance.addToCart(cartLineItem: cartLineItem);
|
||||
showStatusAlert(context,
|
||||
title: trans("Success"),
|
||||
subtitle: trans("Added to cart"),
|
||||
duration: 1,
|
||||
icon: Icons.add_shopping_cart,
|
||||
showStatusAlert(
|
||||
context,
|
||||
title: trans("Success"),
|
||||
subtitle: trans("Added to cart"),
|
||||
duration: 1,
|
||||
icon: Icons.add_shopping_cart,
|
||||
);
|
||||
onSuccess();
|
||||
}
|
||||
|
||||
addQuantityTapped({@required Function onSuccess}) {
|
||||
if (product.manageStock != null && product.manageStock == true) {
|
||||
if (quantity >= product.stockQuantity) {
|
||||
showToastNotification(context,
|
||||
addQuantityTapped({required Function onSuccess}) {
|
||||
if (product!.manageStock != null && product!.manageStock == true) {
|
||||
if (quantity >= product!.stockQuantity!) {
|
||||
showToastNotification(context!,
|
||||
title: trans("Maximum quantity reached"),
|
||||
description:
|
||||
"${trans("Sorry, only")} ${product.stockQuantity} ${trans("left")}",
|
||||
"${trans("Sorry, only")} ${product!.stockQuantity} ${trans("left")}",
|
||||
style: ToastNotificationStyleType.INFO);
|
||||
return;
|
||||
}
|
||||
@ -64,14 +66,16 @@ class ProductDetailController extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
removeQuantityTapped({@required Function onSuccess}) {
|
||||
removeQuantityTapped({required Function onSuccess}) {
|
||||
if ((quantity - 1) >= 1) {
|
||||
quantity--;
|
||||
onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
toggleWishList({@required Function onSuccess, @required WishlistAction wishlistAction}) async {
|
||||
toggleWishList(
|
||||
{required Function onSuccess,
|
||||
required WishlistAction wishlistAction}) async {
|
||||
String subtitleMsg;
|
||||
if (wishlistAction == WishlistAction.remove) {
|
||||
await removeWishlistProduct(product: product);
|
||||
@ -80,7 +84,8 @@ class ProductDetailController extends Controller {
|
||||
await saveWishlistProduct(product: product);
|
||||
subtitleMsg = trans("This product has been added to your wishlist");
|
||||
}
|
||||
showStatusAlert(context,
|
||||
showStatusAlert(
|
||||
context,
|
||||
title: trans("Success"),
|
||||
subtitle: subtitleMsg,
|
||||
icon: Icons.favorite,
|
||||
@ -90,18 +95,18 @@ class ProductDetailController extends Controller {
|
||||
onSuccess();
|
||||
}
|
||||
|
||||
ws_product_variation.ProductVariation findProductVariation(
|
||||
{@required Map<int, dynamic> tmpAttributeObj,
|
||||
@required List<ws_product_variation.ProductVariation> productVariations}) {
|
||||
ws_product_variation.ProductVariation tmpProductVariation;
|
||||
ws_product_variation.ProductVariation? findProductVariation(
|
||||
{required Map<int, dynamic> tmpAttributeObj,
|
||||
required List<ws_product_variation.ProductVariation> productVariations}) {
|
||||
ws_product_variation.ProductVariation? tmpProductVariation;
|
||||
|
||||
Map<String, dynamic> tmpSelectedObj = {};
|
||||
Map<String?, dynamic> tmpSelectedObj = {};
|
||||
for (var attributeObj in tmpAttributeObj.values) {
|
||||
tmpSelectedObj[attributeObj["name"]] = attributeObj["value"];
|
||||
}
|
||||
|
||||
for (var productVariation in productVariations) {
|
||||
Map<String, dynamic> tmpVariations = {};
|
||||
Map<String?, dynamic> tmpVariations = {};
|
||||
|
||||
for (var attr in productVariation.attributes) {
|
||||
tmpVariations[attr.name] = attr.option;
|
||||
@ -114,4 +119,4 @@ class ProductDetailController extends Controller {
|
||||
|
||||
return tmpProductVariation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,25 +1,23 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/product.dart';
|
||||
|
||||
class ProductLoaderController extends WooSignalApiLoaderController<Product> {
|
||||
ProductLoaderController();
|
||||
|
||||
Future<void> loadProducts({
|
||||
@required bool Function(bool hasProducts) hasResults,
|
||||
@required void Function() didFinish,
|
||||
List<int> productIds = const []
|
||||
}) async {
|
||||
Future<void> loadProducts(
|
||||
{required bool Function(bool hasProducts) hasResults,
|
||||
required void Function() didFinish,
|
||||
List<int>? productIds = const []}) async {
|
||||
await load(
|
||||
hasResults: hasResults,
|
||||
didFinish: didFinish,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -12,11 +12,8 @@ import 'controller.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class ProductReviewsController extends Controller {
|
||||
|
||||
@override
|
||||
construct(BuildContext context) {
|
||||
super.construct(context);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,34 +1,34 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
|
||||
import 'package:woosignal/models/response/product_review.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/product.dart';
|
||||
|
||||
class ProductReviewsLoaderController extends WooSignalApiLoaderController<ProductReview> {
|
||||
class ProductReviewsLoaderController
|
||||
extends WooSignalApiLoaderController<ProductReview> {
|
||||
ProductReviewsLoaderController();
|
||||
|
||||
Future<void> loadProductReviews({
|
||||
@required Product product,
|
||||
@required bool Function(bool hasProducts) hasResults,
|
||||
@required void Function() didFinish,
|
||||
required Product? product,
|
||||
required bool Function(bool hasProducts) hasResults,
|
||||
required void Function() didFinish,
|
||||
}) async {
|
||||
await load(
|
||||
hasResults: hasResults,
|
||||
didFinish: didFinish,
|
||||
apiQuery: (api) => api.getProductReviews(
|
||||
product: [product.id],
|
||||
perPage: 50,
|
||||
page: page,
|
||||
status: "approved",
|
||||
));
|
||||
product: [product!.id!],
|
||||
perPage: 50,
|
||||
page: page,
|
||||
status: "approved",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,25 +1,24 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/product.dart';
|
||||
|
||||
class ProductSearchLoaderController
|
||||
extends WooSignalApiLoaderController<Product> {
|
||||
ProductSearchLoaderController();
|
||||
|
||||
Future<void> loadProducts(
|
||||
{@required bool Function(bool hasProducts) hasResults,
|
||||
@required void Function() didFinish,
|
||||
@required String search}) async {
|
||||
{required bool Function(bool hasProducts) hasResults,
|
||||
required void Function() didFinish,
|
||||
required String? search}) async {
|
||||
await load(
|
||||
hasResults: hasResults,
|
||||
didFinish: didFinish,
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:woosignal/woosignal.dart';
|
||||
|
||||
@ -20,15 +19,15 @@ class WooSignalApiLoaderController<T> {
|
||||
WooSignalApiLoaderController();
|
||||
|
||||
Future<void> load(
|
||||
{@required bool Function(bool hasProducts) hasResults,
|
||||
@required void Function() didFinish,
|
||||
@required Future<List<T>> Function(WooSignal query) apiQuery}) async {
|
||||
{required bool Function(bool hasProducts) hasResults,
|
||||
required void Function() didFinish,
|
||||
required Future<List<T>> Function(WooSignal query) apiQuery}) async {
|
||||
if (_waitForNextRequest) {
|
||||
return;
|
||||
}
|
||||
_waitForNextRequest = true;
|
||||
|
||||
List<T> apiResults = await appWooSignal((api) => apiQuery(api));
|
||||
List<T> apiResults = await (appWooSignal((api) => apiQuery(api)));
|
||||
|
||||
if (!hasResults(apiResults.isNotEmpty)) {
|
||||
return;
|
||||
@ -41,9 +40,7 @@ class WooSignalApiLoaderController<T> {
|
||||
didFinish();
|
||||
}
|
||||
|
||||
List<T> getResults() {
|
||||
return _results;
|
||||
}
|
||||
List<T> getResults() => _results;
|
||||
|
||||
void clear() {
|
||||
_results = [];
|
||||
|
||||
15
LabelStoreMax/lib/app/events/login_event.dart
Normal file
@ -0,0 +1,15 @@
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class LoginEvent implements NyEvent {
|
||||
@override
|
||||
final listeners = {
|
||||
DefaultListener: DefaultListener(),
|
||||
};
|
||||
}
|
||||
|
||||
class DefaultListener extends NyListener {
|
||||
@override
|
||||
handle(dynamic event) async {
|
||||
// handle the payload from event
|
||||
}
|
||||
}
|
||||
13
LabelStoreMax/lib/app/events/logout_event.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class LogoutEvent implements NyEvent {
|
||||
@override
|
||||
final listeners = {DefaultListener: DefaultListener()};
|
||||
}
|
||||
|
||||
class DefaultListener extends NyListener {
|
||||
@override
|
||||
handle(dynamic event) async {
|
||||
// handle the payload from event
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -11,12 +11,76 @@
|
||||
import 'package:flutter_app/app/models/customer_address.dart';
|
||||
|
||||
class BillingDetails {
|
||||
CustomerAddress billingAddress;
|
||||
CustomerAddress shippingAddress;
|
||||
bool rememberDetails;
|
||||
CustomerAddress? billingAddress;
|
||||
CustomerAddress? shippingAddress;
|
||||
bool? rememberDetails;
|
||||
|
||||
BillingDetails();
|
||||
|
||||
void initSession() {
|
||||
billingAddress = CustomerAddress();
|
||||
shippingAddress = CustomerAddress();
|
||||
}
|
||||
|
||||
Map<String, dynamic> createStripeDetails() => {
|
||||
'address': {
|
||||
if (billingAddress?.addressLine != null)
|
||||
'line1': billingAddress?.addressLine,
|
||||
if (billingAddress?.city != null) 'city': billingAddress?.city,
|
||||
if (billingAddress?.postalCode != null)
|
||||
'postal_code': billingAddress?.postalCode,
|
||||
if (billingAddress?.customerCountry?.state?.name != null)
|
||||
'state': billingAddress?.customerCountry?.state?.name,
|
||||
if (billingAddress?.customerCountry?.countryCode != null)
|
||||
'country': billingAddress?.customerCountry?.countryCode,
|
||||
},
|
||||
'shipping': {
|
||||
if (shippingAddress?.nameFull() != null)
|
||||
'name': shippingAddress?.nameFull(),
|
||||
if (shippingAddress?.city != null) 'city': shippingAddress?.city,
|
||||
if (shippingAddress?.postalCode != null)
|
||||
'postal_code': shippingAddress?.postalCode,
|
||||
if (shippingAddress?.customerCountry?.state?.name != null)
|
||||
'state': shippingAddress?.customerCountry?.state?.name,
|
||||
if (shippingAddress?.customerCountry?.countryCode != null)
|
||||
'country': shippingAddress?.customerCountry?.countryCode,
|
||||
},
|
||||
if (billingAddress?.emailAddress != null)
|
||||
'email': billingAddress?.emailAddress,
|
||||
if (billingAddress?.nameFull() != null)
|
||||
'name': billingAddress?.nameFull(),
|
||||
if (billingAddress?.phoneNumber != null)
|
||||
'phone': billingAddress?.phoneNumber
|
||||
};
|
||||
|
||||
Map<String, String?> getShippingAddressStripe() => {
|
||||
"name": shippingAddress?.nameFull(),
|
||||
"line1": shippingAddress!.addressLine,
|
||||
"city": shippingAddress!.city,
|
||||
"postal_code": shippingAddress!.postalCode,
|
||||
"country": (shippingAddress?.customerCountry?.name ?? "")
|
||||
};
|
||||
|
||||
fromWpMeta(Map<String, String> data) async {
|
||||
final Map<String, String> shippingDetailsWpMeta = <String, String>{},
|
||||
billingDetailsWpMeta = <String, String>{};
|
||||
|
||||
shippingDetailsWpMeta.addEntries(data.entries
|
||||
.where((element) => element.key.startsWith("shipping_"))
|
||||
.map((shippingMeta) => MapEntry(
|
||||
shippingMeta.key.replaceAll("shipping_", ""), shippingMeta.value)));
|
||||
billingDetailsWpMeta.addEntries(data.entries
|
||||
.where((element) => element.key.startsWith("billing_"))
|
||||
.map((billingMeta) => MapEntry(
|
||||
billingMeta.key.replaceAll("billing_", ""), billingMeta.value)));
|
||||
|
||||
CustomerAddress billingCustomerAddress = CustomerAddress();
|
||||
await billingCustomerAddress.fromWpMetaData(billingDetailsWpMeta);
|
||||
|
||||
CustomerAddress shippingCustomerAddress = CustomerAddress();
|
||||
await shippingCustomerAddress.fromWpMetaData(shippingDetailsWpMeta);
|
||||
|
||||
billingAddress = billingCustomerAddress;
|
||||
shippingAddress = shippingCustomerAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -15,5 +15,8 @@ class BottomNavItem {
|
||||
BottomNavigationBarItem bottomNavigationBarItem;
|
||||
Widget tabWidget;
|
||||
|
||||
BottomNavItem({this.id, this.bottomNavigationBarItem, this.tabWidget});
|
||||
BottomNavItem(
|
||||
{required this.id,
|
||||
required this.bottomNavigationBarItem,
|
||||
required this.tabWidget});
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -10,14 +10,14 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:collection/collection.dart' show IterableExtension;
|
||||
import 'package:flutter_app/app/models/cart_line_item.dart';
|
||||
import 'package:flutter_app/app/models/checkout_session.dart';
|
||||
import 'package:flutter_app/app/models/shipping_type.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
|
||||
import 'package:nylo_support/helpers/helper.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/response/shipping_method.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
|
||||
@ -27,7 +27,7 @@ class Cart {
|
||||
|
||||
Future<List<CartLineItem>> getCart() async {
|
||||
List<CartLineItem> cartLineItems = [];
|
||||
String currentCartArrJSON = await NyStorage.read(SharedKey.cart);
|
||||
String? currentCartArrJSON = await (NyStorage.read(SharedKey.cart));
|
||||
|
||||
if (currentCartArrJSON != null) {
|
||||
cartLineItems = (jsonDecode(currentCartArrJSON) as List<dynamic>)
|
||||
@ -38,15 +38,14 @@ class Cart {
|
||||
return cartLineItems;
|
||||
}
|
||||
|
||||
Future addToCart({@required CartLineItem cartLineItem}) async {
|
||||
Future addToCart({required CartLineItem cartLineItem}) async {
|
||||
List<CartLineItem> cartLineItems = await getCart();
|
||||
|
||||
if (cartLineItem.variationId != null &&
|
||||
cartLineItems.firstWhere(
|
||||
(i) => (i.productId == cartLineItem.productId &&
|
||||
cartLineItems.firstWhereOrNull((i) =>
|
||||
(i.productId == cartLineItem.productId &&
|
||||
i.variationId == cartLineItem.variationId &&
|
||||
i.variationOptions == cartLineItem.variationOptions),
|
||||
orElse: () => null) !=
|
||||
i.variationOptions == cartLineItem.variationOptions)) !=
|
||||
null) {
|
||||
cartLineItems.removeWhere((item) =>
|
||||
item.productId == cartLineItem.productId &&
|
||||
@ -55,8 +54,8 @@ class Cart {
|
||||
}
|
||||
|
||||
if (cartLineItem.variationId == null &&
|
||||
cartLineItems.firstWhere((i) => i.productId == cartLineItem.productId,
|
||||
orElse: () => null) !=
|
||||
cartLineItems.firstWhereOrNull(
|
||||
(i) => i.productId == cartLineItem.productId) !=
|
||||
null) {
|
||||
cartLineItems
|
||||
.removeWhere((item) => item.productId == cartLineItem.productId);
|
||||
@ -80,7 +79,7 @@ class Cart {
|
||||
total = total - double.parse(discountAmount);
|
||||
}
|
||||
|
||||
if (withFormat != null && withFormat == true) {
|
||||
if (withFormat == true) {
|
||||
return formatDoubleCurrency(total: total);
|
||||
}
|
||||
return total.toStringAsFixed(2);
|
||||
@ -92,15 +91,15 @@ class Cart {
|
||||
for (var cartItem in cartLineItems) {
|
||||
subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity);
|
||||
}
|
||||
if (withFormat != null && withFormat == true) {
|
||||
if (withFormat == true) {
|
||||
return formatDoubleCurrency(total: subtotal);
|
||||
}
|
||||
return subtotal.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
updateQuantity(
|
||||
{@required CartLineItem cartLineItem,
|
||||
@required int incrementQuantity}) async {
|
||||
{required CartLineItem cartLineItem,
|
||||
required int incrementQuantity}) async {
|
||||
List<CartLineItem> cartLineItems = await getCart();
|
||||
List<CartLineItem> tmpCartItem = [];
|
||||
for (var cartItem in cartLineItems) {
|
||||
@ -124,7 +123,7 @@ class Cart {
|
||||
.join(",");
|
||||
}
|
||||
|
||||
removeCartItemForIndex({@required int index}) async {
|
||||
removeCartItemForIndex({required int index}) async {
|
||||
List<CartLineItem> cartLineItems = await getCart();
|
||||
cartLineItems.removeAt(index);
|
||||
await saveCartToPref(cartLineItems: cartLineItems);
|
||||
@ -132,12 +131,12 @@ class Cart {
|
||||
|
||||
clear() async => NyStorage.delete(SharedKey.cart);
|
||||
|
||||
saveCartToPref({@required List<CartLineItem> cartLineItems}) async {
|
||||
saveCartToPref({required List<CartLineItem> cartLineItems}) async {
|
||||
String json = jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
|
||||
await NyStorage.store(SharedKey.cart, json);
|
||||
}
|
||||
|
||||
Future<String> taxAmount(TaxRate taxRate) async {
|
||||
Future<String> taxAmount(TaxRate? taxRate) async {
|
||||
double subtotal = 0;
|
||||
double shippingTotal = 0;
|
||||
|
||||
@ -150,7 +149,7 @@ class Cart {
|
||||
cartItems.where((c) => c.taxStatus == 'taxable').toList();
|
||||
double cartSubtotal = 0;
|
||||
|
||||
if (AppHelper.instance.appConfig.productPricesIncludeTax == 1 &&
|
||||
if (AppHelper.instance.appConfig!.productPricesIncludeTax == 1 &&
|
||||
taxableCartLines.isNotEmpty) {
|
||||
cartSubtotal = taxableCartLines
|
||||
.map<double>((m) => parseWcPrice(m.subtotal) * m.quantity)
|
||||
@ -163,22 +162,20 @@ class Cart {
|
||||
|
||||
subtotal = cartSubtotal;
|
||||
|
||||
ShippingType shippingType = CheckoutSession.getInstance.shippingType;
|
||||
ShippingType? shippingType = CheckoutSession.getInstance.shippingType;
|
||||
|
||||
if (shippingType != null) {
|
||||
switch (shippingType.methodId) {
|
||||
case "flat_rate":
|
||||
FlatRate flatRate = (shippingType.object as FlatRate);
|
||||
if (flatRate.taxable != null && flatRate.taxable) {
|
||||
shippingTotal += parseWcPrice(
|
||||
shippingType.cost == null || shippingType.cost == ""
|
||||
? "0"
|
||||
: shippingType.cost);
|
||||
if (flatRate.taxable != null && flatRate.taxable!) {
|
||||
shippingTotal +=
|
||||
parseWcPrice(shippingType.cost == "" ? "0" : shippingType.cost);
|
||||
}
|
||||
break;
|
||||
case "local_pickup":
|
||||
LocalPickup localPickup = (shippingType.object as LocalPickup);
|
||||
if (localPickup.taxable != null && localPickup.taxable) {
|
||||
if (localPickup.taxable != null && localPickup.taxable!) {
|
||||
shippingTotal += parseWcPrice(
|
||||
(localPickup.cost == null || localPickup.cost == ""
|
||||
? "0"
|
||||
@ -192,10 +189,10 @@ class Cart {
|
||||
|
||||
double total = 0;
|
||||
if (subtotal != 0) {
|
||||
total += ((parseWcPrice(taxRate.rate) * subtotal) / 100);
|
||||
total += ((parseWcPrice(taxRate!.rate) * subtotal) / 100);
|
||||
}
|
||||
if (shippingTotal != 0) {
|
||||
total += ((parseWcPrice(taxRate.rate) * shippingTotal) / 100);
|
||||
total += ((parseWcPrice(taxRate!.rate) * shippingTotal) / 100);
|
||||
}
|
||||
return (total).toStringAsFixed(2);
|
||||
}
|
||||
@ -213,10 +210,10 @@ class Cart {
|
||||
for (var cartItem in cartLineItems) {
|
||||
bool canContinue = true;
|
||||
|
||||
if (checkoutSession.coupon.excludedProductCategories.isNotEmpty) {
|
||||
if (checkoutSession.coupon!.excludedProductCategories!.isNotEmpty) {
|
||||
for (var excludedProductCategory
|
||||
in checkoutSession.coupon.excludedProductCategories) {
|
||||
if (cartItem.categories
|
||||
in checkoutSession.coupon!.excludedProductCategories!) {
|
||||
if (cartItem.categories!
|
||||
.map((category) => category.id)
|
||||
.contains(excludedProductCategory)) {
|
||||
canContinue = false;
|
||||
@ -225,10 +222,10 @@ class Cart {
|
||||
}
|
||||
}
|
||||
|
||||
if (checkoutSession.coupon.productCategories.isNotEmpty) {
|
||||
if (checkoutSession.coupon!.productCategories!.isNotEmpty) {
|
||||
for (var productCategories
|
||||
in checkoutSession.coupon.productCategories) {
|
||||
if (cartItem.categories
|
||||
in checkoutSession.coupon!.productCategories!) {
|
||||
if (cartItem.categories!
|
||||
.map((category) => category.id)
|
||||
.contains(productCategories) ==
|
||||
false) {
|
||||
@ -242,41 +239,41 @@ class Cart {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkoutSession.coupon.excludeSaleItems == true &&
|
||||
if (checkoutSession.coupon!.excludeSaleItems == true &&
|
||||
cartItem.onSale == true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkoutSession.coupon.excludedProductIds.isNotEmpty &&
|
||||
checkoutSession.coupon.excludedProductIds
|
||||
if (checkoutSession.coupon!.excludedProductIds!.isNotEmpty &&
|
||||
checkoutSession.coupon!.excludedProductIds!
|
||||
.contains(cartItem.productId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkoutSession.coupon.productIds.isNotEmpty &&
|
||||
!checkoutSession.coupon.productIds.contains(cartItem.productId)) {
|
||||
if (checkoutSession.coupon!.productIds!.isNotEmpty &&
|
||||
!checkoutSession.coupon!.productIds!.contains(cartItem.productId)) {
|
||||
continue;
|
||||
}
|
||||
subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity);
|
||||
eligibleCartLineItems.add(cartItem);
|
||||
}
|
||||
|
||||
String discountType = checkoutSession.coupon.discountType;
|
||||
String amount = checkoutSession.coupon.amount;
|
||||
String? discountType = checkoutSession.coupon!.discountType;
|
||||
String? amount = checkoutSession.coupon!.amount;
|
||||
|
||||
// Percentage
|
||||
if (discountType == 'percent') {
|
||||
return ((subtotal * double.parse(amount)) / 100).toStringAsFixed(2);
|
||||
return ((subtotal * double.parse(amount!)) / 100).toStringAsFixed(2);
|
||||
}
|
||||
|
||||
// Fixed cart
|
||||
if (discountType == 'fixed_cart') {
|
||||
return (double.parse(amount)).toStringAsFixed(2);
|
||||
return (double.parse(amount!)).toStringAsFixed(2);
|
||||
}
|
||||
|
||||
// Fixed product
|
||||
if (discountType == 'fixed_product') {
|
||||
return (eligibleCartLineItems.length * double.parse(amount))
|
||||
return (eligibleCartLineItems.length * double.parse(amount!))
|
||||
.toStringAsFixed(2);
|
||||
}
|
||||
return "0";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -11,27 +11,27 @@
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/response/product_variation.dart';
|
||||
import 'package:woosignal/models/response/products.dart' as ws_product;
|
||||
import 'package:woosignal/models/response/product.dart' as ws_product;
|
||||
|
||||
class CartLineItem {
|
||||
String name;
|
||||
int productId;
|
||||
int variationId;
|
||||
int quantity;
|
||||
bool isManagedStock;
|
||||
int stockQuantity;
|
||||
String shippingClassId;
|
||||
String taxStatus;
|
||||
String taxClass;
|
||||
bool shippingIsTaxable;
|
||||
String subtotal;
|
||||
String total;
|
||||
String imageSrc;
|
||||
String variationOptions;
|
||||
List<ws_product.Category> categories;
|
||||
bool onSale;
|
||||
String stockStatus;
|
||||
Object metaData = {};
|
||||
String? name;
|
||||
int? productId;
|
||||
int? variationId;
|
||||
int quantity = 0;
|
||||
bool? isManagedStock;
|
||||
int? stockQuantity;
|
||||
String? shippingClassId;
|
||||
String? taxStatus;
|
||||
String? taxClass;
|
||||
bool? shippingIsTaxable;
|
||||
String? subtotal;
|
||||
String? total;
|
||||
String? imageSrc;
|
||||
String? variationOptions;
|
||||
List<ws_product.Category>? categories;
|
||||
bool? onSale;
|
||||
String? stockStatus;
|
||||
Object? metaData = {};
|
||||
|
||||
CartLineItem(
|
||||
{this.name,
|
||||
@ -39,7 +39,7 @@ class CartLineItem {
|
||||
this.variationId,
|
||||
this.isManagedStock,
|
||||
this.stockQuantity,
|
||||
this.quantity,
|
||||
this.quantity = 1,
|
||||
this.stockStatus,
|
||||
this.shippingClassId,
|
||||
this.taxStatus,
|
||||
@ -57,10 +57,11 @@ class CartLineItem {
|
||||
return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2);
|
||||
}
|
||||
|
||||
CartLineItem.fromProduct({int quantityAmount, ws_product.Product product}) {
|
||||
CartLineItem.fromProduct(
|
||||
{int? quantityAmount, required ws_product.Product product}) {
|
||||
name = product.name;
|
||||
productId = product.id;
|
||||
quantity = quantityAmount;
|
||||
quantity = quantityAmount ?? 1;
|
||||
taxStatus = product.taxStatus;
|
||||
shippingClassId = product.shippingClassId.toString();
|
||||
subtotal = product.price;
|
||||
@ -76,21 +77,21 @@ class CartLineItem {
|
||||
}
|
||||
|
||||
CartLineItem.fromProductVariation(
|
||||
{int quantityAmount,
|
||||
List<String> options,
|
||||
ws_product.Product product,
|
||||
ProductVariation productVariation}) {
|
||||
String imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE");
|
||||
{int? quantityAmount,
|
||||
required List<String> options,
|
||||
required ws_product.Product product,
|
||||
required ProductVariation productVariation}) {
|
||||
String? imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE");
|
||||
if (product.images.isNotEmpty) {
|
||||
imageSrc = product.images.first.src;
|
||||
}
|
||||
if (productVariation.image != null) {
|
||||
imageSrc = productVariation.image.src;
|
||||
imageSrc = productVariation.image!.src;
|
||||
}
|
||||
name = product.name;
|
||||
productId = product.id;
|
||||
variationId = productVariation.id;
|
||||
quantity = quantityAmount;
|
||||
quantity = quantityAmount ?? 1;
|
||||
taxStatus = productVariation.taxStatus;
|
||||
shippingClassId = productVariation.shippingClassId.toString();
|
||||
subtotal = productVariation.price;
|
||||
@ -145,7 +146,7 @@ class CartLineItem {
|
||||
'shipping_is_taxable': shippingIsTaxable,
|
||||
'image_src': imageSrc,
|
||||
'categories': categories != null
|
||||
? categories.map((e) => e.toJson()).toList()
|
||||
? categories!.map((e) => e.toJson()).toList()
|
||||
: [],
|
||||
'variation_options': variationOptions,
|
||||
'subtotal': subtotal,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -16,21 +16,21 @@ import 'package:flutter_app/app/models/payment_type.dart';
|
||||
import 'package:flutter_app/app/models/shipping_type.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
|
||||
import 'package:nylo_support/helpers/helper.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/response/coupon.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
|
||||
class CheckoutSession {
|
||||
bool shipToDifferentAddress = false;
|
||||
bool? shipToDifferentAddress = false;
|
||||
|
||||
CheckoutSession._privateConstructor();
|
||||
static final CheckoutSession getInstance =
|
||||
CheckoutSession._privateConstructor();
|
||||
|
||||
BillingDetails billingDetails;
|
||||
ShippingType shippingType;
|
||||
PaymentType paymentType;
|
||||
Coupon coupon;
|
||||
BillingDetails? billingDetails;
|
||||
ShippingType? shippingType;
|
||||
PaymentType? paymentType;
|
||||
Coupon? coupon;
|
||||
|
||||
void initSession() {
|
||||
billingDetails = BillingDetails();
|
||||
@ -45,8 +45,8 @@ class CheckoutSession {
|
||||
}
|
||||
|
||||
saveBillingAddress() async {
|
||||
CustomerAddress customerAddress =
|
||||
CheckoutSession.getInstance.billingDetails.billingAddress;
|
||||
CustomerAddress? customerAddress =
|
||||
CheckoutSession.getInstance.billingDetails!.billingAddress;
|
||||
|
||||
if (customerAddress == null) {
|
||||
return;
|
||||
@ -56,9 +56,9 @@ class CheckoutSession {
|
||||
await NyStorage.store(SharedKey.customerBillingDetails, billingAddress);
|
||||
}
|
||||
|
||||
Future<CustomerAddress> getBillingAddress() async {
|
||||
String strCheckoutDetails =
|
||||
await NyStorage.read(SharedKey.customerBillingDetails);
|
||||
Future<CustomerAddress?> getBillingAddress() async {
|
||||
String? strCheckoutDetails =
|
||||
await (NyStorage.read(SharedKey.customerBillingDetails));
|
||||
|
||||
if (strCheckoutDetails != null && strCheckoutDetails != "") {
|
||||
return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails));
|
||||
@ -70,8 +70,8 @@ class CheckoutSession {
|
||||
await NyStorage.delete(SharedKey.customerBillingDetails);
|
||||
|
||||
saveShippingAddress() async {
|
||||
CustomerAddress customerAddress =
|
||||
CheckoutSession.getInstance.billingDetails.shippingAddress;
|
||||
CustomerAddress? customerAddress =
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress;
|
||||
if (customerAddress == null) {
|
||||
return;
|
||||
}
|
||||
@ -79,9 +79,9 @@ class CheckoutSession {
|
||||
await NyStorage.store(SharedKey.customerShippingDetails, shippingAddress);
|
||||
}
|
||||
|
||||
Future<CustomerAddress> getShippingAddress() async {
|
||||
String strCheckoutDetails =
|
||||
await NyStorage.read(SharedKey.customerShippingDetails);
|
||||
Future<CustomerAddress?> getShippingAddress() async {
|
||||
String? strCheckoutDetails =
|
||||
await (NyStorage.read(SharedKey.customerShippingDetails));
|
||||
if (strCheckoutDetails != null && strCheckoutDetails != "") {
|
||||
return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails));
|
||||
}
|
||||
@ -91,19 +91,19 @@ class CheckoutSession {
|
||||
clearShippingAddress() async =>
|
||||
await NyStorage.delete(SharedKey.customerShippingDetails);
|
||||
|
||||
Future<String> total({bool withFormat = false, TaxRate taxRate}) async {
|
||||
Future<String> total({bool withFormat = false, TaxRate? taxRate}) async {
|
||||
double totalCart = parseWcPrice(await Cart.getInstance.getTotal());
|
||||
double totalShipping = 0;
|
||||
if (shippingType != null && shippingType.object != null) {
|
||||
switch (shippingType.methodId) {
|
||||
if (shippingType != null && shippingType!.object != null) {
|
||||
switch (shippingType!.methodId) {
|
||||
case "flat_rate":
|
||||
totalShipping = parseWcPrice(shippingType.cost);
|
||||
totalShipping = parseWcPrice(shippingType!.cost);
|
||||
break;
|
||||
case "free_shipping":
|
||||
totalShipping = parseWcPrice(shippingType.cost);
|
||||
totalShipping = parseWcPrice(shippingType!.cost);
|
||||
break;
|
||||
case "local_pickup":
|
||||
totalShipping = parseWcPrice(shippingType.cost);
|
||||
totalShipping = parseWcPrice(shippingType!.cost);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -9,16 +9,19 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter_app/app/models/customer_country.dart';
|
||||
import 'package:flutter_app/app/models/default_shipping.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:wp_json_api/models/wp_meta_meta.dart';
|
||||
|
||||
class CustomerAddress {
|
||||
String firstName;
|
||||
String lastName;
|
||||
String addressLine;
|
||||
String city;
|
||||
String postalCode;
|
||||
String emailAddress;
|
||||
String phoneNumber;
|
||||
CustomerCountry customerCountry;
|
||||
String? firstName;
|
||||
String? lastName;
|
||||
String? addressLine;
|
||||
String? city;
|
||||
String? postalCode;
|
||||
String? emailAddress;
|
||||
String? phoneNumber;
|
||||
CustomerCountry? customerCountry;
|
||||
|
||||
CustomerAddress(
|
||||
{this.firstName,
|
||||
@ -27,7 +30,7 @@ class CustomerAddress {
|
||||
this.city,
|
||||
this.postalCode,
|
||||
this.emailAddress,
|
||||
this.phoneNumber,
|
||||
this.phoneNumber,
|
||||
this.customerCountry});
|
||||
|
||||
void initAddress() {
|
||||
@ -42,17 +45,17 @@ class CustomerAddress {
|
||||
}
|
||||
|
||||
bool hasMissingFields() =>
|
||||
(firstName.isEmpty ||
|
||||
lastName.isEmpty ||
|
||||
addressLine.isEmpty ||
|
||||
city.isEmpty ||
|
||||
postalCode.isEmpty) ||
|
||||
(customerCountry.hasState() == true
|
||||
(firstName!.isEmpty ||
|
||||
lastName!.isEmpty ||
|
||||
addressLine!.isEmpty ||
|
||||
city!.isEmpty ||
|
||||
postalCode!.isEmpty) ||
|
||||
(customerCountry!.hasState() == true
|
||||
? (customerCountry?.state?.name ?? "").isEmpty
|
||||
: false);
|
||||
|
||||
String addressFull() {
|
||||
List<String> tmpArrAddress = [];
|
||||
List<String?> tmpArrAddress = [];
|
||||
if (addressLine != null && addressLine != "") {
|
||||
tmpArrAddress.add(addressLine);
|
||||
}
|
||||
@ -66,13 +69,13 @@ class CustomerAddress {
|
||||
tmpArrAddress.add(customerCountry?.state?.name);
|
||||
}
|
||||
if (customerCountry != null && customerCountry?.name != null) {
|
||||
tmpArrAddress.add(customerCountry.name);
|
||||
tmpArrAddress.add(customerCountry!.name);
|
||||
}
|
||||
return tmpArrAddress.join(", ");
|
||||
}
|
||||
|
||||
String nameFull() {
|
||||
List<String> tmpArrName = [];
|
||||
List<String?> tmpArrName = [];
|
||||
if (firstName != "") {
|
||||
tmpArrName.add(firstName);
|
||||
}
|
||||
@ -102,16 +105,73 @@ class CustomerAddress {
|
||||
data['address_line'] = addressLine;
|
||||
data['city'] = city;
|
||||
data['postal_code'] = postalCode;
|
||||
data['state'] = customerCountry.state;
|
||||
data['country'] = customerCountry.name;
|
||||
data['state'] = customerCountry!.state;
|
||||
data['country'] = customerCountry!.name;
|
||||
if (phoneNumber != null && phoneNumber != "") {
|
||||
data['phone_number'] = phoneNumber;
|
||||
}
|
||||
data['email_address'] = emailAddress;
|
||||
data['customer_country'] = null;
|
||||
if (customerCountry != null) {
|
||||
data['customer_country'] = customerCountry.toJson();
|
||||
data['customer_country'] = customerCountry!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
fromWpMetaData(Map<String, dynamic> data) async {
|
||||
if (data.containsKey('first_name')) {
|
||||
firstName = data['first_name'];
|
||||
}
|
||||
|
||||
if (data.containsKey('last_name')) {
|
||||
lastName = data['last_name'];
|
||||
}
|
||||
|
||||
if (data.containsKey('address_1')) {
|
||||
addressLine = data['address_1'];
|
||||
}
|
||||
|
||||
if (data.containsKey('city')) {
|
||||
city = data['city'];
|
||||
}
|
||||
|
||||
if (data.containsKey('postcode')) {
|
||||
postalCode = data['postcode'];
|
||||
}
|
||||
|
||||
if (data.containsKey('email')) {
|
||||
emailAddress = data['email'];
|
||||
}
|
||||
|
||||
if (data.containsKey('phone')) {
|
||||
phoneNumber = data['phone'];
|
||||
}
|
||||
|
||||
if (data.containsKey('country')) {
|
||||
DefaultShipping? defaultShipping =
|
||||
await findCountryMetaForShipping(data['country']);
|
||||
if (defaultShipping == null) {
|
||||
return;
|
||||
}
|
||||
customerCountry = CustomerCountry.fromWpMeta(data, defaultShipping);
|
||||
}
|
||||
}
|
||||
|
||||
List<WpMetaData> toUserMetaDataItem(String type) {
|
||||
return [
|
||||
WpMetaData(key: "${type}_first_name", value: firstName),
|
||||
WpMetaData(key: "${type}_last_name", value: lastName),
|
||||
WpMetaData(key: "${type}_address_1", value: addressLine),
|
||||
WpMetaData(key: "${type}_city", value: city),
|
||||
WpMetaData(key: "${type}_postcode", value: postalCode),
|
||||
WpMetaData(key: "${type}_phone", value: phoneNumber),
|
||||
if (type != "shipping")
|
||||
WpMetaData(key: "${type}_email", value: emailAddress),
|
||||
WpMetaData(key: "${type}_country", value: customerCountry?.countryCode),
|
||||
WpMetaData(
|
||||
key: "${type}_state",
|
||||
value: customerCountry?.state?.code
|
||||
?.replaceAll("${customerCountry?.countryCode}:", "")),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -9,23 +9,33 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter_app/app/models/default_shipping.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
|
||||
class CustomerCountry {
|
||||
String countryCode;
|
||||
String name;
|
||||
DefaultShippingState state;
|
||||
String? countryCode;
|
||||
String? name;
|
||||
DefaultShippingState? state;
|
||||
|
||||
CustomerCountry({this.countryCode, this.name, this.state});
|
||||
|
||||
CustomerCountry.fromDefaultShipping({DefaultShipping defaultShipping}) {
|
||||
CustomerCountry.fromDefaultShipping(
|
||||
{required DefaultShipping defaultShipping}) {
|
||||
countryCode = defaultShipping.code;
|
||||
name = defaultShipping.country;
|
||||
if ((defaultShipping.states?.length ?? 0) == 1) {
|
||||
if ((defaultShipping.states.length) == 1) {
|
||||
state = defaultShipping.states.first;
|
||||
}
|
||||
}
|
||||
|
||||
CustomerCountry.fromJson(Map<String, dynamic> json) {
|
||||
CustomerCountry.fromWpMeta(
|
||||
Map<String, dynamic> json, DefaultShipping defaultShipping) {
|
||||
countryCode = json['country'];
|
||||
name = defaultShipping.country;
|
||||
state = findDefaultShippingStateByCode(
|
||||
defaultShipping, "${json['country']}:${json['state']}");
|
||||
}
|
||||
|
||||
CustomerCountry.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) {
|
||||
return;
|
||||
}
|
||||
@ -40,7 +50,7 @@ class CustomerCountry {
|
||||
}
|
||||
}
|
||||
|
||||
bool hasState() => (state != null && state.name != null ? true : false);
|
||||
bool hasState() => (state != null && state!.name != null ? true : false);
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
@ -48,7 +58,7 @@ class CustomerCountry {
|
||||
data['name'] = name;
|
||||
data['state'] = null;
|
||||
if (state != null) {
|
||||
data['state'] = state.toJson();
|
||||
data['state'] = state!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -1,28 +1,25 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class DefaultShipping {
|
||||
String code;
|
||||
String country;
|
||||
String? country;
|
||||
List<DefaultShippingState> states;
|
||||
DefaultShipping(
|
||||
{@required this.code, @required this.country, @required this.states});
|
||||
{required this.code, required this.country, required this.states});
|
||||
}
|
||||
|
||||
class DefaultShippingState {
|
||||
String code;
|
||||
String name;
|
||||
String? code;
|
||||
String? name;
|
||||
|
||||
DefaultShippingState({@required this.code, @required this.name});
|
||||
DefaultShippingState({required this.code, required this.name});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class PaymentType {
|
||||
int id;
|
||||
String name;
|
||||
@ -18,9 +16,9 @@ class PaymentType {
|
||||
Function pay;
|
||||
|
||||
PaymentType(
|
||||
{@required this.id,
|
||||
@required this.name,
|
||||
@required this.desc,
|
||||
@required this.assetImage,
|
||||
@required this.pay});
|
||||
{required this.id,
|
||||
required this.name,
|
||||
required this.desc,
|
||||
required this.assetImage,
|
||||
required this.pay});
|
||||
}
|
||||
|
||||
@ -1,28 +1,26 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:woosignal/models/response/shipping_method.dart';
|
||||
|
||||
class ShippingType {
|
||||
String methodId;
|
||||
String? methodId;
|
||||
String cost;
|
||||
String minimumValue;
|
||||
String? minimumValue;
|
||||
dynamic object;
|
||||
|
||||
ShippingType(
|
||||
{@required this.methodId,
|
||||
{required this.methodId,
|
||||
this.object,
|
||||
@required this.cost,
|
||||
@required this.minimumValue});
|
||||
required this.cost,
|
||||
required this.minimumValue});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'methodId': methodId,
|
||||
@ -31,24 +29,24 @@ class ShippingType {
|
||||
'minimumValue': minimumValue
|
||||
};
|
||||
|
||||
String getTotal({bool withFormatting = false}) {
|
||||
String? getTotal({bool withFormatting = false}) {
|
||||
if (object != null) {
|
||||
switch (methodId) {
|
||||
case "flat_rate":
|
||||
FlatRate flatRate = (object as FlatRate);
|
||||
FlatRate? flatRate = (object as FlatRate?);
|
||||
return (withFormatting == true
|
||||
? formatStringCurrency(total: cost)
|
||||
: flatRate.cost);
|
||||
: flatRate!.cost);
|
||||
case "free_shipping":
|
||||
FreeShipping freeShipping = (object as FreeShipping);
|
||||
FreeShipping? freeShipping = (object as FreeShipping?);
|
||||
return (withFormatting == true
|
||||
? formatStringCurrency(total: cost)
|
||||
: freeShipping.cost);
|
||||
: freeShipping!.cost);
|
||||
case "local_pickup":
|
||||
LocalPickup localPickup = (object as LocalPickup);
|
||||
LocalPickup? localPickup = (object as LocalPickup?);
|
||||
return (withFormatting == true
|
||||
? formatStringCurrency(total: cost)
|
||||
: localPickup.cost);
|
||||
: localPickup!.cost);
|
||||
default:
|
||||
return "0";
|
||||
}
|
||||
@ -56,7 +54,7 @@ class ShippingType {
|
||||
return "0";
|
||||
}
|
||||
|
||||
String getTitle() {
|
||||
String? getTitle() {
|
||||
if (object != null) {
|
||||
switch (methodId) {
|
||||
case "flat_rate":
|
||||
@ -75,7 +73,7 @@ class ShippingType {
|
||||
return "";
|
||||
}
|
||||
|
||||
Map<String, dynamic> toShippingLineFee() {
|
||||
Map<String, dynamic>? toShippingLineFee() {
|
||||
if (object != null) {
|
||||
Map<String, dynamic> tmpShippingLinesObj = {};
|
||||
|
||||
|
||||
@ -1,27 +1,25 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:nylo_support/helpers/helper.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class User extends Storable {
|
||||
String userId;
|
||||
String token;
|
||||
class User extends Model {
|
||||
String? userId;
|
||||
String? token;
|
||||
|
||||
User();
|
||||
User.fromUserAuthResponse({this.userId, this.token});
|
||||
|
||||
@override
|
||||
toStorage() => {"token": token, "user_id": userId};
|
||||
toJson() => {"token": token, "user_id": userId};
|
||||
|
||||
@override
|
||||
fromStorage(dynamic data) {
|
||||
User.fromJson(dynamic data) {
|
||||
token = data['token'];
|
||||
userId = data['user_id'];
|
||||
}
|
||||
|
||||
@ -1,11 +1,29 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/networking/dio/base_api_service.dart';
|
||||
import 'package:flutter_app/app/networking/dio/interceptors/logging_interceptor.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ApiService
|
||||
| -------------------------------------------------------------------------
|
||||
| Define your API endpoints
|
||||
| Learn more https://nylo.dev/docs/5.x/networking
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
class ApiService {}
|
||||
class ApiService extends BaseApiService {
|
||||
ApiService({BuildContext? buildContext}) : super(buildContext);
|
||||
|
||||
@override
|
||||
String get baseUrl => getEnv('API_BASE_URL');
|
||||
|
||||
@override
|
||||
final interceptors = {LoggingInterceptor: LoggingInterceptor()};
|
||||
|
||||
Future<dynamic> fetchTestData() async {
|
||||
return await network(
|
||||
request: (request) => request.get("/endpoint-path"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
19
LabelStoreMax/lib/app/networking/dio/base_api_service.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/networking/dio/interceptors/logging_interceptor.dart';
|
||||
import 'package:flutter_app/config/decoders.dart';
|
||||
import 'package:nylo_framework/networking/ny_base_networking.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class BaseApiService extends NyBaseApiService {
|
||||
BaseApiService(BuildContext? context) : super(context);
|
||||
|
||||
/// Map decoders to modelDecoders
|
||||
@override
|
||||
final Map<Type, dynamic> decoders = modelDecoders;
|
||||
|
||||
/// Default interceptors
|
||||
@override
|
||||
final interceptors = {
|
||||
if (getEnv('APP_DEBUG') == true) LoggingInterceptor: LoggingInterceptor()
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class BearerAuthInterceptor extends Interceptor {
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
String? userToken = Backpack.instance.read('user_token');
|
||||
if (userToken != null) {
|
||||
options.headers.addAll({"Authorization": "Bearer $userToken"});
|
||||
}
|
||||
return super.onRequest(options, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(Response response, ResponseInterceptorHandler handler) {
|
||||
handler.next(response);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
handler.next(err);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
import 'dart:developer';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class LoggingInterceptor extends Interceptor {
|
||||
@override
|
||||
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||
print('REQUEST[${options.method}] => PATH: ${options.path}');
|
||||
return super.onRequest(options, handler);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(Response response, ResponseInterceptorHandler handler) {
|
||||
print(
|
||||
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
|
||||
print('DATA: ${response.requestOptions.path}');
|
||||
log(response.data.toString());
|
||||
handler.next(response);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||
print(
|
||||
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
|
||||
handler.next(err);
|
||||
}
|
||||
}
|
||||
107
LabelStoreMax/lib/app/providers/app_provider.dart
Normal file
@ -0,0 +1,107 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/config/decoders.dart';
|
||||
import 'package:flutter_app/config/design.dart';
|
||||
import 'package:flutter_app/config/theme.dart';
|
||||
import 'package:flutter_app/config/validation_rules.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:flutter_app/config/localization.dart';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
import 'package:woosignal/woosignal.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
class AppProvider implements NyProvider {
|
||||
@override
|
||||
boot(Nylo nylo) async {
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
]);
|
||||
|
||||
await WooSignal.instance
|
||||
.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG'),
|
||||
encryptKey: getEnv('ENCRYPT_KEY', defaultValue: null),
|
||||
encryptSecret: getEnv('ENCRYPT_SECRET', defaultValue: null)
|
||||
);
|
||||
|
||||
AppHelper.instance.appConfig = WooSignalApp();
|
||||
AppHelper.instance.appConfig!.themeFont = "Poppins";
|
||||
AppHelper.instance.appConfig!.themeColors = {
|
||||
'light': {
|
||||
'background': '0xFFFFFFFF',
|
||||
'primary_text': '0xFF000000',
|
||||
'button_background': '0xFF529cda',
|
||||
'button_text': '0xFFFFFFFF',
|
||||
'app_bar_background': '0xFFFFFFFF',
|
||||
'app_bar_text': '0xFF3a3d40',
|
||||
},
|
||||
'dark': {
|
||||
'background': '0xFF212121',
|
||||
'primary_text': '0xFFE1E1E1',
|
||||
'button_background': '0xFFFFFFFF',
|
||||
'button_text': '0xFF232c33',
|
||||
'app_bar_background': '0xFF2C2C2C',
|
||||
'app_bar_text': '0xFFFFFFFF',
|
||||
}
|
||||
};
|
||||
|
||||
// WooSignal Setup
|
||||
WooSignalApp? wooSignalApp = await (appWooSignal((api) => api.getApp(encrypted: shouldEncrypt())));
|
||||
Locale locale = Locale('en');
|
||||
|
||||
if (wooSignalApp != null) {
|
||||
AppHelper.instance.appConfig = wooSignalApp;
|
||||
|
||||
if (wooSignalApp.wpLoginEnabled == 1) {
|
||||
if (wooSignalApp.wpLoginBaseUrl == null) {
|
||||
AppHelper.instance.appConfig?.wpLoginEnabled = 0;
|
||||
log('Set your stores domain on WooSignal. Go to Features > WP Login and add your domain to "Store Base Url"');
|
||||
}
|
||||
|
||||
if (wooSignalApp.wpLoginWpApiPath == null) {
|
||||
AppHelper.instance.appConfig?.wpLoginEnabled = 0;
|
||||
log('Set your stores Wp JSON path on WooSignal. Go to Features > WP Login and add your Wp JSON path to "WP API Path"');
|
||||
}
|
||||
|
||||
WPJsonAPI.instance.initWith(
|
||||
baseUrl: wooSignalApp.wpLoginBaseUrl ?? "",
|
||||
shouldDebug: getEnv('APP_DEBUG'),
|
||||
wpJsonPath: wooSignalApp.wpLoginWpApiPath ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null &&
|
||||
wooSignalApp.locale != null) {
|
||||
locale = Locale(wooSignalApp.locale!);
|
||||
} else {
|
||||
locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en'));
|
||||
}
|
||||
}
|
||||
|
||||
/// NyLocalization
|
||||
await NyLocalization.instance.init(
|
||||
localeType: localeType,
|
||||
languageCode: locale.languageCode,
|
||||
languagesList: languagesList,
|
||||
assetsDirectory: assetsDirectory,
|
||||
valuesAsMap: valuesAsMap);
|
||||
|
||||
nylo.appThemes = appThemes;
|
||||
nylo.appLoader = loader;
|
||||
nylo.appLogo = logo;
|
||||
|
||||
nylo.addModelDecoders(modelDecoders);
|
||||
nylo.addValidationRules(validationRules);
|
||||
nylo.toastNotification = getToastNotificationWidget;
|
||||
|
||||
return nylo;
|
||||
}
|
||||
|
||||
@override
|
||||
afterBoot(Nylo nylo) async {
|
||||
|
||||
}
|
||||
}
|
||||
16
LabelStoreMax/lib/app/providers/event_provider.dart
Normal file
@ -0,0 +1,16 @@
|
||||
import 'package:flutter_app/config/events.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class EventProvider implements NyProvider {
|
||||
@override
|
||||
boot(Nylo nylo) async {
|
||||
nylo.addEvents(events);
|
||||
|
||||
return nylo;
|
||||
}
|
||||
|
||||
@override
|
||||
afterBoot(Nylo nylo) async {
|
||||
|
||||
}
|
||||
}
|
||||
49
LabelStoreMax/lib/app/providers/firebase_provider.dart
Normal file
@ -0,0 +1,49 @@
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/firebase_options.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/woosignal.dart';
|
||||
|
||||
class FirebaseProvider implements NyProvider {
|
||||
|
||||
@override
|
||||
boot(Nylo nylo) async {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
afterBoot(Nylo nylo) async {
|
||||
bool? firebaseFcmIsEnabled = AppHelper.instance.appConfig?.firebaseFcmIsEnabled;
|
||||
if (firebaseFcmIsEnabled == null) {
|
||||
firebaseFcmIsEnabled = getEnv('FCM_ENABLED', defaultValue: false);
|
||||
}
|
||||
|
||||
if (firebaseFcmIsEnabled != true) return;
|
||||
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
|
||||
FirebaseMessaging messaging = FirebaseMessaging.instance;
|
||||
NotificationSettings settings = await messaging.requestPermission(
|
||||
alert: true,
|
||||
announcement: false,
|
||||
badge: true,
|
||||
carPlay: false,
|
||||
criticalAlert: false,
|
||||
provisional: false,
|
||||
sound: true,
|
||||
);
|
||||
|
||||
if (settings.authorizationStatus != AuthorizationStatus.authorized) {
|
||||
return;
|
||||
}
|
||||
|
||||
String? token = await messaging.getToken();
|
||||
if (token != null) {
|
||||
WooSignal.instance.setFcmToken(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -14,18 +14,18 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
import 'package:woosignal/models/response/order.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
|
||||
cashOnDeliveryPay(context,
|
||||
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
try {
|
||||
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: false);
|
||||
|
||||
Order order = await appWooSignal((api) => api.createOrder(orderWC));
|
||||
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
|
||||
|
||||
if (order != null) {
|
||||
Navigator.pushNamed(context, "/checkout-status", arguments: order);
|
||||
@ -3,7 +3,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -14,7 +14,7 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
import 'package:woosignal/models/response/order.dart';
|
||||
@ -29,11 +29,19 @@ import 'package:woosignal/models/response/tax_rate.dart';
|
||||
//
|
||||
// });
|
||||
|
||||
// REMEMBER TO ADD THIS METHOD E.G. "examplePay" TO THE APP_PAYMENT_METHODS
|
||||
// AS THE PAY METHOD
|
||||
// TO USE A PAYMENT GATEWAY, FIRST OPEN /config/payment_gateways.dart.
|
||||
// THEN ADD A NEW PAYMENT LIKE IN THE BELOW EXAMPLE
|
||||
//
|
||||
// addPayment(
|
||||
// id: 6,
|
||||
// name: "My Payment",
|
||||
// description: trans("Debit or Credit Card"),
|
||||
// assetImage: "payment_logo.png", E.g. /public/assets/images/payment_logo.png
|
||||
// pay: examplePay,
|
||||
// ),
|
||||
|
||||
examplePay(context,
|
||||
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
// HANDLE YOUR PAYMENT INTEGRATION HERE
|
||||
// ...
|
||||
// ...
|
||||
@ -44,7 +52,7 @@ examplePay(context,
|
||||
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true);
|
||||
|
||||
// CREATES ORDER IN WOOCOMMERCE
|
||||
Order order = await appWooSignal((api) => api.createOrder(orderWC));
|
||||
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
|
||||
|
||||
// CHECK IF ORDER IS NULL
|
||||
if (order != null) {
|
||||
@ -3,7 +3,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -15,7 +15,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/cart_line_item.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:flutter_app/resources/widgets/checkout_paypal.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
@ -23,7 +23,7 @@ import 'package:woosignal/models/response/order.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
|
||||
payPalPay(context,
|
||||
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
await checkout(taxRate, (total, billingDetails, cart) async {
|
||||
List<CartLineItem> cartLineItems = await cart.getCart();
|
||||
String description = await cart.cartShortDesc();
|
||||
@ -35,7 +35,7 @@ payPalPay(context,
|
||||
description: description,
|
||||
amount: total,
|
||||
cartLineItems: cartLineItems))).then((value) async {
|
||||
if (!(value is Map<String, dynamic>)) {
|
||||
if (value is! Map<String, dynamic>) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Payment Cancelled"),
|
||||
@ -48,7 +48,7 @@ payPalPay(context,
|
||||
state.reloadState(showLoader: true);
|
||||
if (value.containsKey("status") && value["status"] == "success") {
|
||||
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true);
|
||||
Order order = await appWooSignal((api) => api.createOrder(orderWC));
|
||||
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
|
||||
|
||||
if (order == null) {
|
||||
showToastNotification(
|
||||
81
LabelStoreMax/lib/app/providers/payments/razorpay_pay.dart
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// LabelCore
|
||||
// Label StoreMAX
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_app/app/models/cart.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
import 'package:woosignal/models/response/order.dart';
|
||||
|
||||
razorPay(context,
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
Razorpay razorpay = Razorpay();
|
||||
|
||||
razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS,
|
||||
(PaymentSuccessResponse response) async {
|
||||
OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
|
||||
|
||||
Order? order = await appWooSignal((api) => api.createOrder(orderWC));
|
||||
|
||||
if (order != null) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: "Error".tr(),
|
||||
description: trans("Something went wrong, please contact our store"),
|
||||
);
|
||||
state.reloadState(showLoader: false);
|
||||
return;
|
||||
}
|
||||
Cart.getInstance.clear();
|
||||
Navigator.pushNamed(context, "/checkout-status", arguments: order);
|
||||
});
|
||||
|
||||
razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) {
|
||||
showToastNotification(context,
|
||||
title: trans("Error"),
|
||||
description: response.message ?? "",
|
||||
style: ToastNotificationStyleType.WARNING);
|
||||
state.reloadState(showLoader: false);
|
||||
});
|
||||
|
||||
razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
|
||||
|
||||
// CHECKOUT HELPER
|
||||
await checkout(taxRate, (total, billingDetails, cart) async {
|
||||
var options = {
|
||||
'key': getEnv('RAZORPAY_API_KEY'),
|
||||
'amount': (double.parse(total) * 100).toInt(),
|
||||
'name': getEnv('APP_NAME'),
|
||||
'description': await cart.cartShortDesc(),
|
||||
'prefill': {
|
||||
"name": [
|
||||
billingDetails!.billingAddress?.firstName,
|
||||
billingDetails.billingAddress?.lastName
|
||||
].where((t) => t != null || t != "").toList().join(" "),
|
||||
"method": "card",
|
||||
'email': billingDetails.billingAddress?.emailAddress ?? ""
|
||||
}
|
||||
};
|
||||
|
||||
state.reloadState(showLoader: true);
|
||||
|
||||
razorpay.open(options);
|
||||
});
|
||||
}
|
||||
|
||||
void _handleExternalWallet(ExternalWalletResponse response) {}
|
||||
@ -3,7 +3,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -15,7 +15,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
@ -24,16 +24,16 @@ import 'package:woosignal/models/response/tax_rate.dart';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
|
||||
stripePay(context,
|
||||
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
|
||||
WooSignalApp wooSignalApp = AppHelper.instance.appConfig;
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
WooSignalApp? wooSignalApp = AppHelper.instance.appConfig;
|
||||
|
||||
bool liveMode = getEnv('STRIPE_LIVE_MODE') == null
|
||||
? !wooSignalApp.stripeLiveMode
|
||||
? !wooSignalApp!.stripeLiveMode!
|
||||
: getEnv('STRIPE_LIVE_MODE', defaultValue: false);
|
||||
|
||||
// CONFIGURE STRIPE
|
||||
Stripe.stripeAccountId =
|
||||
getEnv('STRIPE_ACCOUNT') ?? wooSignalApp.stripeAccount;
|
||||
getEnv('STRIPE_ACCOUNT') ?? wooSignalApp!.stripeAccount;
|
||||
|
||||
Stripe.publishableKey = liveMode
|
||||
? "pk_live_IyS4Vt86L49jITSfaUShumzi"
|
||||
@ -47,24 +47,17 @@ stripePay(context,
|
||||
}
|
||||
|
||||
try {
|
||||
dynamic rsp = {};
|
||||
Map<String, dynamic>? rsp = {};
|
||||
// // CHECKOUT HELPER
|
||||
await checkout(taxRate, (total, billingDetails, cart) async {
|
||||
Map<String, dynamic> address = {
|
||||
"name": billingDetails.billingAddress.nameFull(),
|
||||
"line1": billingDetails.shippingAddress.addressLine,
|
||||
"city": billingDetails.shippingAddress.city,
|
||||
"postal_code": billingDetails.shippingAddress.postalCode,
|
||||
"country": (billingDetails.shippingAddress?.customerCountry?.name ?? "")
|
||||
};
|
||||
|
||||
String cartShortDesc = await cart.cartShortDesc();
|
||||
|
||||
rsp = await appWooSignal((api) => api.stripePaymentIntent(
|
||||
rsp = await appWooSignal((api) => api.stripePaymentIntentV2(
|
||||
amount: total,
|
||||
email: billingDetails.billingAddress.emailAddress,
|
||||
email: billingDetails?.billingAddress?.emailAddress,
|
||||
desc: cartShortDesc,
|
||||
shipping: address,
|
||||
shipping: billingDetails?.getShippingAddressStripe(),
|
||||
customerDetails: billingDetails?.createStripeDetails(),
|
||||
));
|
||||
});
|
||||
|
||||
@ -79,26 +72,41 @@ stripePay(context,
|
||||
}
|
||||
|
||||
await Stripe.instance.initPaymentSheet(
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
applePay: false,
|
||||
googlePay: false,
|
||||
style: Theme.of(state.context).brightness == Brightness.light
|
||||
? ThemeMode.light
|
||||
: ThemeMode.dark,
|
||||
testEnv: liveMode,
|
||||
merchantCountryCode: envVal('STRIPE_COUNTRY_CODE',
|
||||
defaultValue: wooSignalApp.stripeCountryCode),
|
||||
merchantDisplayName:
|
||||
envVal('APP_NAME', defaultValue: wooSignalApp.appName),
|
||||
paymentIntentClientSecret: rsp['client_secret'],
|
||||
));
|
||||
paymentSheetParameters: SetupPaymentSheetParameters(
|
||||
style: Theme.of(state.context).brightness == Brightness.light
|
||||
? ThemeMode.light
|
||||
: ThemeMode.dark,
|
||||
merchantDisplayName:
|
||||
envVal('APP_NAME', defaultValue: wooSignalApp?.appName),
|
||||
customerId: rsp!['customer'],
|
||||
paymentIntentClientSecret: rsp!['client_secret'],
|
||||
customerEphemeralKeySecret: rsp!['ephemeral_key'],
|
||||
setupIntentClientSecret: rsp!['setup_intent_secret']),
|
||||
);
|
||||
|
||||
await Stripe.instance.presentPaymentSheet();
|
||||
|
||||
PaymentIntent paymentIntent =
|
||||
await Stripe.instance.retrievePaymentIntent(rsp!['client_secret']);
|
||||
|
||||
if (paymentIntent.status == PaymentIntentsStatus.Unknown) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong, please try again."),
|
||||
icon: Icons.payment,
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
}
|
||||
|
||||
if (paymentIntent.status != PaymentIntentsStatus.Succeeded) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.reloadState(showLoader: true);
|
||||
|
||||
OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
|
||||
Order order = await appWooSignal((api) => api.createOrder(orderWC));
|
||||
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
|
||||
|
||||
if (order == null) {
|
||||
showToastNotification(
|
||||
@ -110,15 +118,15 @@ stripePay(context,
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.pushNamed(context, "/checkout-status", arguments: order);
|
||||
routeTo('/checkout-status', navigationType: NavigationType.pushAndForgetAll, data: order);
|
||||
} on StripeException catch (e) {
|
||||
if (getEnv('APP_DEBUG', defaultValue: true)) {
|
||||
NyLogger.error(e.error.message);
|
||||
NyLogger.error(e.error.message!);
|
||||
}
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops!"),
|
||||
description: e.error.localizedMessage,
|
||||
description: e.error.localizedMessage!,
|
||||
icon: Icons.payment,
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
20
LabelStoreMax/lib/app/providers/route_provider.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/routes/router.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class RouteProvider implements NyProvider {
|
||||
@override
|
||||
boot(Nylo nylo) async {
|
||||
nylo.addRouter(appRouter());
|
||||
|
||||
return nylo;
|
||||
}
|
||||
|
||||
@override
|
||||
afterBoot(Nylo nylo) async {
|
||||
String initialRoute = AppHelper.instance.appConfig!.appStatus != null
|
||||
? '/home'
|
||||
: '/no-connection';
|
||||
nylo.setInitialRoute(initialRoute);
|
||||
}
|
||||
}
|
||||
@ -1,42 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/config/app_theme.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class AppBuild extends StatelessWidget {
|
||||
String initialRoute;
|
||||
ThemeData themeData;
|
||||
ThemeData darkTheme;
|
||||
ThemeData lightTheme;
|
||||
Locale locale;
|
||||
String title;
|
||||
String? initialRoute;
|
||||
ThemeData? themeData;
|
||||
ThemeData? darkTheme;
|
||||
ThemeData? lightTheme;
|
||||
Locale? locale;
|
||||
String? title;
|
||||
bool debugShowCheckedModeBanner;
|
||||
bool debugShowMaterialGrid;
|
||||
bool showPerformanceOverlay;
|
||||
bool checkerboardRasterCacheImages;
|
||||
bool checkerboardOffscreenLayers;
|
||||
bool showSemanticsDebugger;
|
||||
Map<LogicalKeySet, Intent> shortcuts;
|
||||
Map<Type, Action<Intent>> actions;
|
||||
Map<LogicalKeySet, Intent>? shortcuts;
|
||||
Map<Type, Action<Intent>>? actions;
|
||||
List<Locale> supportedLocales;
|
||||
ThemeMode themeMode;
|
||||
Color color;
|
||||
GenerateAppTitle onGenerateTitle;
|
||||
TransitionBuilder builder;
|
||||
Color? color;
|
||||
GenerateAppTitle? onGenerateTitle;
|
||||
TransitionBuilder? builder;
|
||||
List<NavigatorObserver> navigatorObservers;
|
||||
RouteFactory onUnknownRoute;
|
||||
InitialRouteListFactory onGenerateInitialRoutes;
|
||||
GlobalKey<NavigatorState> navigatorKey;
|
||||
RouteFactory? onUnknownRoute;
|
||||
InitialRouteListFactory? onGenerateInitialRoutes;
|
||||
GlobalKey<NavigatorState>? navigatorKey;
|
||||
|
||||
Route<dynamic> Function(RouteSettings settings) onGenerateRoute;
|
||||
Route<dynamic>? Function(RouteSettings settings) onGenerateRoute;
|
||||
|
||||
AppBuild({
|
||||
Key key,
|
||||
Key? key,
|
||||
this.initialRoute,
|
||||
this.title,
|
||||
this.locale,
|
||||
this.themeData,
|
||||
@required this.onGenerateRoute,
|
||||
required this.onGenerateRoute,
|
||||
this.navigatorKey,
|
||||
this.onGenerateInitialRoutes,
|
||||
this.onUnknownRoute,
|
||||
@ -60,14 +59,12 @@ class AppBuild extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Nylo nylo = Backpack.instance.read('nylo');
|
||||
List<AppTheme> appThemes =
|
||||
nylo.appThemes.map((appTheme) => appTheme.toAppTheme()).toList();
|
||||
return LocalizedApp(
|
||||
child: ThemeProvider(
|
||||
themes: appThemes
|
||||
.map((appTheme) => appTheme.toAppTheme(
|
||||
defaultTheme: appTheme.theme.brightness == Brightness.light
|
||||
? lightTheme
|
||||
: darkTheme))
|
||||
.toList(),
|
||||
themes: appThemes,
|
||||
child: ThemeConsumer(
|
||||
child: Builder(
|
||||
builder: (themeContext) => ValueListenableBuilder(
|
||||
@ -93,16 +90,20 @@ class AppBuild extends StatelessWidget {
|
||||
title: title ?? "",
|
||||
initialRoute: initialRoute,
|
||||
onGenerateRoute: onGenerateRoute,
|
||||
darkTheme: darkTheme ?? ThemeConfig.dark().theme,
|
||||
darkTheme: darkTheme ??
|
||||
appThemes
|
||||
.firstWhere(
|
||||
(theme) => theme.id == getEnv('DARK_THEME_ID'),
|
||||
orElse: () => appThemes.first)
|
||||
.data,
|
||||
theme: themeData ?? ThemeProvider.themeOf(context).data,
|
||||
localeResolutionCallback:
|
||||
(Locale locale, Iterable<Locale> supportedLocales) {
|
||||
(Locale? locale, Iterable<Locale> supportedLocales) {
|
||||
return locale;
|
||||
},
|
||||
localizationsDelegates: NyLocalization.instance.delegates,
|
||||
locale: NyLocalization.instance.locale,
|
||||
supportedLocales:
|
||||
supportedLocales ?? NyLocalization.instance.locals(),
|
||||
supportedLocales: supportedLocales,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -15,5 +15,5 @@ class AppHelper {
|
||||
|
||||
static final AppHelper instance = AppHelper._privateConstructor();
|
||||
|
||||
WooSignalApp appConfig;
|
||||
WooSignalApp? appConfig;
|
||||
}
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class BaseThemeConfig {
|
||||
final String id;
|
||||
final String description;
|
||||
final ThemeData theme;
|
||||
final BaseColorStyles colors;
|
||||
final dynamic meta;
|
||||
|
||||
BaseThemeConfig(
|
||||
{this.id,
|
||||
this.description,
|
||||
this.theme,
|
||||
this.colors,
|
||||
this.meta = const {}});
|
||||
|
||||
AppTheme toAppTheme({ThemeData defaultTheme}) => AppTheme(
|
||||
id: id,
|
||||
data: defaultTheme ?? theme,
|
||||
description: description,
|
||||
);
|
||||
}
|
||||
@ -1,96 +1,8 @@
|
||||
// import 'package:firebase_core/firebase_core.dart';
|
||||
// import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
// import 'package:flutter_app/firebase_options.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/config/app_localization.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
import 'package:woosignal/woosignal.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
/// boot application
|
||||
Future<void> boot() async {
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
]);
|
||||
import 'package:flutter_app/config/providers.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
await WooSignal.instance
|
||||
.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG'));
|
||||
|
||||
// Notifications
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
///
|
||||
/// FirebaseMessaging messaging = FirebaseMessaging.instance;
|
||||
///
|
||||
/// NotificationSettings settings = await messaging.requestPermission(
|
||||
/// alert: true,
|
||||
/// announcement: false,
|
||||
/// badge: true,
|
||||
/// carPlay: false,
|
||||
/// criticalAlert: false,
|
||||
/// provisional: false,
|
||||
/// sound: true,
|
||||
/// );
|
||||
///
|
||||
/// if (settings.authorizationStatus == AuthorizationStatus.authorized) {
|
||||
/// String token = await messaging.getToken();
|
||||
/// WooSignal.instance.setFcmToken(token);
|
||||
/// }
|
||||
|
||||
AppHelper?.instance?.appConfig = WooSignalApp();
|
||||
AppHelper.instance.appConfig.themeFont = "Poppins";
|
||||
AppHelper.instance.appConfig.themeColors = {
|
||||
'light': {
|
||||
'background': '0xFFFFFFFF',
|
||||
'primary_text': '0xFF000000',
|
||||
'button_background': '0xFF529cda',
|
||||
'button_text': '0xFFFFFFFF',
|
||||
'app_bar_background': '0xFFFFFFFF',
|
||||
'app_bar_text': '0xFF3a3d40',
|
||||
},
|
||||
'dark': {
|
||||
'background': '0xFF212121',
|
||||
'primary_text': '0xFFE1E1E1',
|
||||
'button_background': '0xFFFFFFFF',
|
||||
'button_text': '0xFF232c33',
|
||||
'app_bar_background': '0xFF2C2C2C',
|
||||
'app_bar_text': '0xFFFFFFFF',
|
||||
}
|
||||
};
|
||||
|
||||
// WooSignal Setup
|
||||
WooSignalApp wooSignalApp = await appWooSignal((api) => api.getApp());
|
||||
Locale locale = Locale('en');
|
||||
|
||||
if (wooSignalApp != null) {
|
||||
AppHelper.instance.appConfig = wooSignalApp;
|
||||
|
||||
if (wooSignalApp.wpLoginEnabled == 1) {
|
||||
WPJsonAPI.instance.initWith(
|
||||
baseUrl: wooSignalApp.wpLoginBaseUrl,
|
||||
shouldDebug: getEnv('APP_DEBUG'),
|
||||
wpJsonPath: wooSignalApp.wpLoginWpApiPath,
|
||||
);
|
||||
}
|
||||
|
||||
if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null &&
|
||||
wooSignalApp.locale != null) {
|
||||
locale = Locale(wooSignalApp.locale);
|
||||
} else {
|
||||
locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en'));
|
||||
}
|
||||
}
|
||||
|
||||
/// NyLocalization
|
||||
await NyLocalization.instance.init(
|
||||
localeType: localeType,
|
||||
languageCode: locale.languageCode,
|
||||
languagesList: languagesList,
|
||||
assetsDirectory: assetsDirectory,
|
||||
valuesAsMap: valuesAsMap);
|
||||
class Boot {
|
||||
static Future<Nylo> nylo() async => await bootApplication(providers);
|
||||
static Future<void> finished(Nylo nylo) async => await bootFinished(nylo, providers);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -15,17 +15,18 @@ import 'package:flutter_app/app/models/cart.dart';
|
||||
import 'package:flutter_app/app/models/cart_line_item.dart';
|
||||
import 'package:flutter_app/app/models/checkout_session.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
|
||||
Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
|
||||
Future<OrderWC> buildOrderWC({TaxRate? taxRate, bool markPaid = true}) async {
|
||||
CheckoutSession checkoutSession = CheckoutSession.getInstance;
|
||||
OrderWC orderWC = OrderWC();
|
||||
WooSignalApp wooSignalApp = AppHelper.instance.appConfig;
|
||||
WooSignalApp wooSignalApp = AppHelper.instance.appConfig!;
|
||||
|
||||
String paymentMethodName = checkoutSession.paymentType.name ?? "";
|
||||
String paymentMethodName = checkoutSession.paymentType!.name;
|
||||
|
||||
orderWC.paymentMethod = Platform.isAndroid
|
||||
? "$paymentMethodName - Android App"
|
||||
@ -35,9 +36,10 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
|
||||
|
||||
orderWC.setPaid = markPaid;
|
||||
orderWC.status = "pending";
|
||||
orderWC.currency = wooSignalApp.currencyMeta.code.toUpperCase();
|
||||
orderWC.customerId =
|
||||
(wooSignalApp.wpLoginEnabled == 1) ? int.parse(await readUserId()) : 0;
|
||||
orderWC.currency = wooSignalApp.currencyMeta!.code!.toUpperCase();
|
||||
orderWC.customerId = (wooSignalApp.wpLoginEnabled == 1)
|
||||
? int.parse(await (readUserId()) ?? "0")
|
||||
: 0;
|
||||
|
||||
List<LineItems> lineItems = [];
|
||||
List<CartLineItem> cartItems = await Cart.getInstance.getCart();
|
||||
@ -50,55 +52,56 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
|
||||
tmpLineItem.variationId = cartItem.variationId;
|
||||
}
|
||||
|
||||
tmpLineItem.subtotal = cartItem.subtotal;
|
||||
tmpLineItem.subtotal = (parseWcPrice(cartItem.subtotal) * parseWcPrice(cartItem.quantity.toString())).toString();
|
||||
lineItems.add(tmpLineItem);
|
||||
}
|
||||
|
||||
orderWC.lineItems = lineItems;
|
||||
|
||||
BillingDetails billingDetails = checkoutSession.billingDetails;
|
||||
BillingDetails billingDetails = checkoutSession.billingDetails!;
|
||||
|
||||
Billing billing = Billing();
|
||||
billing.firstName = billingDetails.billingAddress.firstName;
|
||||
billing.lastName = billingDetails.billingAddress.lastName;
|
||||
billing.address1 = billingDetails.billingAddress.addressLine;
|
||||
billing.city = billingDetails.billingAddress.city;
|
||||
billing.postcode = billingDetails.billingAddress.postalCode;
|
||||
billing.email = billingDetails.billingAddress.emailAddress;
|
||||
if (billingDetails.billingAddress.phoneNumber != "") {
|
||||
billing.phone = billingDetails.billingAddress.phoneNumber;
|
||||
billing.firstName = billingDetails.billingAddress?.firstName;
|
||||
billing.lastName = billingDetails.billingAddress?.lastName;
|
||||
billing.address1 = billingDetails.billingAddress?.addressLine;
|
||||
billing.city = billingDetails.billingAddress?.city;
|
||||
billing.postcode = billingDetails.billingAddress?.postalCode;
|
||||
billing.email = billingDetails.billingAddress?.emailAddress;
|
||||
if (billingDetails.billingAddress?.phoneNumber != "") {
|
||||
billing.phone = billingDetails.billingAddress?.phoneNumber;
|
||||
}
|
||||
if (billingDetails.billingAddress.customerCountry.hasState()) {
|
||||
billing.state = billingDetails.billingAddress.customerCountry.state.name;
|
||||
if (billingDetails.billingAddress?.customerCountry?.hasState() ?? false) {
|
||||
billing.state = billingDetails.billingAddress?.customerCountry!.state!.name;
|
||||
}
|
||||
billing.country = billingDetails.billingAddress.customerCountry.name;
|
||||
billing.country = billingDetails.billingAddress?.customerCountry!.name;
|
||||
|
||||
orderWC.billing = billing;
|
||||
|
||||
Shipping shipping = Shipping();
|
||||
|
||||
shipping.firstName = billingDetails.shippingAddress.firstName;
|
||||
shipping.lastName = billingDetails.shippingAddress.lastName;
|
||||
shipping.address1 = billingDetails.shippingAddress.addressLine;
|
||||
shipping.city = billingDetails.shippingAddress.city;
|
||||
shipping.postcode = billingDetails.shippingAddress.postalCode;
|
||||
if (billingDetails.shippingAddress.customerCountry.hasState()) {
|
||||
billing.state = billingDetails.shippingAddress.customerCountry.state.name;
|
||||
shipping.firstName = billingDetails.shippingAddress!.firstName;
|
||||
shipping.lastName = billingDetails.shippingAddress!.lastName;
|
||||
shipping.address1 = billingDetails.shippingAddress!.addressLine;
|
||||
shipping.city = billingDetails.shippingAddress!.city;
|
||||
shipping.postcode = billingDetails.shippingAddress!.postalCode;
|
||||
if (billingDetails.shippingAddress!.customerCountry!.hasState()) {
|
||||
billing.state =
|
||||
billingDetails.shippingAddress!.customerCountry!.state!.name;
|
||||
}
|
||||
billing.country = billingDetails.shippingAddress.customerCountry.name;
|
||||
billing.country = billingDetails.shippingAddress!.customerCountry!.name;
|
||||
|
||||
orderWC.shipping = shipping;
|
||||
|
||||
orderWC.shippingLines = [];
|
||||
if (wooSignalApp.disableShipping != 1) {
|
||||
Map<String, dynamic> shippingLineFeeObj =
|
||||
checkoutSession.shippingType.toShippingLineFee();
|
||||
Map<String, dynamic>? shippingLineFeeObj =
|
||||
checkoutSession.shippingType!.toShippingLineFee();
|
||||
if (shippingLineFeeObj != null) {
|
||||
ShippingLines shippingLine = ShippingLines();
|
||||
shippingLine.methodId = shippingLineFeeObj['method_id'];
|
||||
shippingLine.methodTitle = shippingLineFeeObj['method_title'];
|
||||
shippingLine.total = shippingLineFeeObj['total'];
|
||||
orderWC.shippingLines.add(shippingLine);
|
||||
orderWC.shippingLines!.add(shippingLine);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,13 +112,13 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
|
||||
feeLines.total = await Cart.getInstance.taxAmount(taxRate);
|
||||
feeLines.taxClass = "";
|
||||
feeLines.taxStatus = "taxable";
|
||||
orderWC.feeLines.add(feeLines);
|
||||
orderWC.feeLines!.add(feeLines);
|
||||
}
|
||||
|
||||
if (checkoutSession.coupon != null) {
|
||||
orderWC.couponLines = [];
|
||||
CouponLines couponLine = CouponLines(code: checkoutSession.coupon.code);
|
||||
orderWC.couponLines.add(couponLine);
|
||||
CouponLines couponLine = CouponLines(code: checkoutSession.coupon!.code);
|
||||
orderWC.couponLines!.add(couponLine);
|
||||
}
|
||||
|
||||
return orderWC;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
|
||||
enum WishlistAction {
|
||||
add,
|
||||
remove
|
||||
}
|
||||
enum WishlistAction { add, remove }
|
||||
|
||||
49
LabelStoreMax/lib/bootstrap/extensions.dart
Normal file
@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/color_styles.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
extension NyText on Text {
|
||||
/// Sets the color from your [ColorStyles] or [Color].
|
||||
Text setColor(
|
||||
BuildContext context, Color Function(ColorStyles color) newColor,
|
||||
{String? themeId}) {
|
||||
return copyWith(
|
||||
style: TextStyle(
|
||||
color: newColor(ThemeColor.get(context, themeId: themeId))));
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the [Product] is new.
|
||||
extension DateTimeExtension on DateTime? {
|
||||
bool? isAfterOrEqualTo(DateTime dateTime) {
|
||||
final date = this;
|
||||
if (date != null) {
|
||||
final isAtSameMomentAs = dateTime.isAtSameMomentAs(date);
|
||||
return isAtSameMomentAs | date.isAfter(dateTime);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool? isBeforeOrEqualTo(DateTime dateTime) {
|
||||
final date = this;
|
||||
if (date != null) {
|
||||
final isAtSameMomentAs = dateTime.isAtSameMomentAs(date);
|
||||
return isAtSameMomentAs | date.isBefore(dateTime);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool? isBetween(
|
||||
DateTime fromDateTime,
|
||||
DateTime toDateTime,
|
||||
) {
|
||||
final date = this;
|
||||
if (date != null) {
|
||||
final isAfter = date.isAfterOrEqualTo(fromDateTime) ?? false;
|
||||
final isBefore = date.isBeforeOrEqualTo(toDateTime) ?? false;
|
||||
return isAfter && isBefore;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -9,6 +9,7 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:collection/collection.dart' show IterableExtension;
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/models/billing_details.dart';
|
||||
import 'package:flutter_app/app/models/cart.dart';
|
||||
@ -19,11 +20,12 @@ import 'package:flutter_app/app/models/payment_type.dart';
|
||||
import 'package:flutter_app/app/models/user.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
|
||||
import 'package:flutter_app/bootstrap/extensions.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
|
||||
import 'package:flutter_app/config/app_currency.dart';
|
||||
import 'package:flutter_app/config/app_payment_gateways.dart';
|
||||
import 'package:flutter_app/config/app_theme.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
|
||||
import 'package:flutter_app/config/currency.dart';
|
||||
import 'package:flutter_app/config/decoders.dart';
|
||||
import 'package:flutter_app/config/events.dart';
|
||||
import 'package:flutter_app/config/payment_gateways.dart';
|
||||
import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
@ -34,65 +36,81 @@ import 'package:flutter_web_browser/flutter_web_browser.dart';
|
||||
import 'package:math_expressions/math_expressions.dart';
|
||||
import 'package:money_formatter/money_formatter.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:platform_alert_dialog/platform_alert_dialog.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
|
||||
import 'package:status_alert/status_alert.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/product.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
import 'package:woosignal/woosignal.dart';
|
||||
import 'package:wp_json_api/models/responses/wp_user_info_response.dart';
|
||||
import '../resources/themes/styles/color_styles.dart';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
|
||||
Future<User> getUser() async =>
|
||||
(await NyStorage.read<User>(SharedKey.authUser, model: User()));
|
||||
Future<User?> getUser() async =>
|
||||
(await (NyStorage.read<User>(SharedKey.authUser)));
|
||||
|
||||
Future appWooSignal(Function(WooSignal) api) async {
|
||||
Future appWooSignal(Function(WooSignal api) api) async {
|
||||
return await api(WooSignal.instance);
|
||||
}
|
||||
|
||||
/// helper to find correct color from the [context].
|
||||
class ThemeColor {
|
||||
static BaseColorStyles get(BuildContext context) {
|
||||
return ((Theme.of(context).brightness == Brightness.light)
|
||||
? ThemeConfig.light().colors
|
||||
: ThemeConfig.dark().colors);
|
||||
static ColorStyles get(BuildContext context, {String? themeId}) {
|
||||
Nylo nylo = Backpack.instance.read('nylo');
|
||||
List<BaseThemeConfig<ColorStyles>> appThemes =
|
||||
nylo.appThemes as List<BaseThemeConfig<ColorStyles>>;
|
||||
|
||||
if (themeId == null) {
|
||||
BaseThemeConfig<ColorStyles> themeFound = appThemes.firstWhere(
|
||||
(theme) =>
|
||||
theme.id ==
|
||||
getEnv(Theme.of(context).brightness == Brightness.light
|
||||
? 'LIGHT_THEME_ID'
|
||||
: 'DARK_THEME_ID'),
|
||||
orElse: () => appThemes.first);
|
||||
return themeFound.colors;
|
||||
}
|
||||
|
||||
BaseThemeConfig<ColorStyles> baseThemeConfig = appThemes.firstWhere(
|
||||
(theme) => theme.id == themeId,
|
||||
orElse: () => appThemes.first);
|
||||
return baseThemeConfig.colors;
|
||||
}
|
||||
}
|
||||
|
||||
/// helper to set colors on TextStyle
|
||||
extension ColorsHelper on TextStyle {
|
||||
TextStyle setColor(
|
||||
BuildContext context, Color Function(BaseColorStyles color) newColor) {
|
||||
BuildContext context, Color Function(BaseColorStyles? color) newColor) {
|
||||
return copyWith(color: newColor(ThemeColor.get(context)));
|
||||
}
|
||||
}
|
||||
|
||||
List<PaymentType> getPaymentTypes() {
|
||||
List<PaymentType> paymentTypes = [];
|
||||
for (var appPaymentGateway in app_payment_gateways) {
|
||||
Future<List<PaymentType?>> getPaymentTypes() async {
|
||||
List<PaymentType?> paymentTypes = [];
|
||||
for (var appPaymentGateway in appPaymentGateways) {
|
||||
if (paymentTypes.firstWhere(
|
||||
(paymentType) => paymentType.name != appPaymentGateway,
|
||||
(paymentType) => paymentType!.name != appPaymentGateway,
|
||||
orElse: () => null) ==
|
||||
null) {
|
||||
paymentTypes.add(paymentTypeList.firstWhere(
|
||||
(paymentTypeList) => paymentTypeList.name == appPaymentGateway,
|
||||
orElse: () => null));
|
||||
paymentTypes.add(paymentTypeList.firstWhereOrNull(
|
||||
(paymentTypeList) => paymentTypeList.name == appPaymentGateway));
|
||||
}
|
||||
}
|
||||
|
||||
if (!app_payment_gateways.contains('Stripe') &&
|
||||
AppHelper.instance.appConfig.stripeEnabled == true) {
|
||||
if (!appPaymentGateways.contains('Stripe') &&
|
||||
AppHelper.instance.appConfig!.stripeEnabled == true) {
|
||||
paymentTypes.add(paymentTypeList
|
||||
.firstWhere((element) => element.name == "Stripe", orElse: () => null));
|
||||
.firstWhereOrNull((element) => element.name == "Stripe"));
|
||||
}
|
||||
if (!app_payment_gateways.contains('PayPal') &&
|
||||
AppHelper.instance.appConfig.paypalEnabled == true) {
|
||||
if (!appPaymentGateways.contains('PayPal') &&
|
||||
AppHelper.instance.appConfig!.paypalEnabled == true) {
|
||||
paymentTypes.add(paymentTypeList
|
||||
.firstWhere((element) => element.name == "PayPal", orElse: () => null));
|
||||
.firstWhereOrNull((element) => element.name == "PayPal"));
|
||||
}
|
||||
if (!app_payment_gateways.contains('CashOnDelivery') &&
|
||||
AppHelper.instance.appConfig.codEnabled == true) {
|
||||
paymentTypes.add(paymentTypeList.firstWhere(
|
||||
(element) => element.name == "CashOnDelivery",
|
||||
orElse: () => null));
|
||||
if (!appPaymentGateways.contains('CashOnDelivery') &&
|
||||
AppHelper.instance.appConfig!.codEnabled == true) {
|
||||
paymentTypes.add(paymentTypeList
|
||||
.firstWhereOrNull((element) => element.name == "CashOnDelivery"));
|
||||
}
|
||||
|
||||
return paymentTypes.where((v) => v != null).toList();
|
||||
@ -102,21 +120,24 @@ dynamic envVal(String envVal, {dynamic defaultValue}) =>
|
||||
(getEnv(envVal) ?? defaultValue);
|
||||
|
||||
PaymentType addPayment(
|
||||
{@required int id,
|
||||
@required String name,
|
||||
@required String desc,
|
||||
@required String assetImage,
|
||||
@required Function pay}) =>
|
||||
{required int id,
|
||||
required String name,
|
||||
required String description,
|
||||
required String assetImage,
|
||||
required Function pay}) =>
|
||||
PaymentType(
|
||||
id: id,
|
||||
name: name,
|
||||
desc: desc,
|
||||
desc: description,
|
||||
assetImage: assetImage,
|
||||
pay: pay,
|
||||
);
|
||||
|
||||
showStatusAlert(context,
|
||||
{@required String title, String subtitle, IconData icon, int duration}) {
|
||||
{required String title,
|
||||
required String subtitle,
|
||||
IconData? icon,
|
||||
int? duration}) {
|
||||
StatusAlert.show(
|
||||
context,
|
||||
duration: Duration(seconds: duration ?? 2),
|
||||
@ -126,31 +147,32 @@ showStatusAlert(context,
|
||||
);
|
||||
}
|
||||
|
||||
String parseHtmlString(String htmlString) {
|
||||
String parseHtmlString(String? htmlString) {
|
||||
var document = parse(htmlString);
|
||||
return parse(document.body.text).documentElement.text;
|
||||
return parse(document.body!.text).documentElement!.text;
|
||||
}
|
||||
|
||||
String moneyFormatter(double amount) {
|
||||
MoneyFormatter fmf = MoneyFormatter(
|
||||
amount: amount,
|
||||
settings: MoneyFormatterSettings(
|
||||
symbol: AppHelper.instance.appConfig.currencyMeta.symbolNative,
|
||||
symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative,
|
||||
symbolAndNumberSeparator: ""
|
||||
),
|
||||
);
|
||||
if (app_currency_symbol_position == SymbolPositionType.left) {
|
||||
if (appCurrencySymbolPosition == SymbolPositionType.left) {
|
||||
return fmf.output.symbolOnLeft;
|
||||
} else if (app_currency_symbol_position == SymbolPositionType.right) {
|
||||
} else if (appCurrencySymbolPosition == SymbolPositionType.right) {
|
||||
return fmf.output.symbolOnRight;
|
||||
}
|
||||
return fmf.output.symbolOnLeft;
|
||||
}
|
||||
|
||||
String formatDoubleCurrency({@required double total}) {
|
||||
String formatDoubleCurrency({required double total}) {
|
||||
return moneyFormatter(total);
|
||||
}
|
||||
|
||||
String formatStringCurrency({@required String total}) {
|
||||
String formatStringCurrency({required String? total}) {
|
||||
double tmpVal = 0;
|
||||
if (total != null && total != "") {
|
||||
tmpVal = parseWcPrice(total);
|
||||
@ -159,20 +181,24 @@ String formatStringCurrency({@required String total}) {
|
||||
}
|
||||
|
||||
String workoutSaleDiscount(
|
||||
{@required String salePrice, @required String priceBefore}) {
|
||||
{required String? salePrice, required String? priceBefore}) {
|
||||
double dSalePrice = parseWcPrice(salePrice);
|
||||
double dPriceBefore = parseWcPrice(priceBefore);
|
||||
return ((dPriceBefore - dSalePrice) * (100 / dPriceBefore))
|
||||
.toStringAsFixed(0);
|
||||
}
|
||||
|
||||
openBrowserTab({@required String url}) async {
|
||||
openBrowserTab({required String url}) async {
|
||||
await FlutterWebBrowser.openWebPage(
|
||||
url: url,
|
||||
customTabsOptions: CustomTabsOptions(toolbarColor: Colors.white70));
|
||||
url: url,
|
||||
customTabsOptions: CustomTabsOptions(
|
||||
defaultColorSchemeParams:
|
||||
CustomTabsColorSchemeParams(toolbarColor: Colors.white70),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool isNumeric(String str) {
|
||||
bool isNumeric(String? str) {
|
||||
if (str == null) {
|
||||
return false;
|
||||
}
|
||||
@ -180,18 +206,18 @@ bool isNumeric(String str) {
|
||||
}
|
||||
|
||||
checkout(
|
||||
TaxRate taxRate,
|
||||
Function(String total, BillingDetails billingDetails, Cart cart)
|
||||
TaxRate? taxRate,
|
||||
Function(String total, BillingDetails? billingDetails, Cart cart)
|
||||
completeCheckout) async {
|
||||
String cartTotal = await CheckoutSession.getInstance
|
||||
.total(withFormat: false, taxRate: taxRate);
|
||||
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails;
|
||||
BillingDetails? billingDetails = CheckoutSession.getInstance.billingDetails;
|
||||
Cart cart = Cart.getInstance;
|
||||
return await completeCheckout(cartTotal, billingDetails, cart);
|
||||
}
|
||||
|
||||
double strCal({@required String sum}) {
|
||||
if (sum == null || sum == "") {
|
||||
double? strCal({required String sum}) {
|
||||
if (sum == "") {
|
||||
return 0;
|
||||
}
|
||||
Parser p = Parser();
|
||||
@ -200,7 +226,7 @@ double strCal({@required String sum}) {
|
||||
return exp.evaluate(EvaluationType.REAL, cm);
|
||||
}
|
||||
|
||||
Future<double> workoutShippingCostWC({@required String sum}) async {
|
||||
Future<double?> workoutShippingCostWC({required String? sum}) async {
|
||||
if (sum == null || sum == "") {
|
||||
return 0;
|
||||
}
|
||||
@ -219,27 +245,27 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
|
||||
if (replace.groupCount < 1) {
|
||||
return "()";
|
||||
}
|
||||
String newSum = replace.group(1);
|
||||
String newSum = replace.group(1)!;
|
||||
|
||||
// PERCENT
|
||||
String percentVal = newSum.replaceAllMapped(
|
||||
defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) {
|
||||
if (replacePercent != null && replacePercent.groupCount >= 1) {
|
||||
if (replacePercent.groupCount >= 1) {
|
||||
String strPercentage = "( (" +
|
||||
orderTotal.toString() +
|
||||
" * " +
|
||||
replacePercent.group(1).toString() +
|
||||
") / 100 )";
|
||||
double calPercentage = strCal(sum: strPercentage);
|
||||
double? calPercentage = strCal(sum: strPercentage);
|
||||
|
||||
// MIN
|
||||
String strRegexMinFee = r'min_fee="([0-9\.]+)"';
|
||||
if (defaultRegex(strRegexMinFee).hasMatch(newSum)) {
|
||||
String strMinFee =
|
||||
defaultRegex(strRegexMinFee).firstMatch(newSum).group(1) ?? "0";
|
||||
defaultRegex(strRegexMinFee).firstMatch(newSum)!.group(1) ?? "0";
|
||||
double doubleMinFee = double.parse(strMinFee);
|
||||
|
||||
if (calPercentage < doubleMinFee) {
|
||||
if (calPercentage! < doubleMinFee) {
|
||||
return "(" + doubleMinFee.toString() + ")";
|
||||
}
|
||||
newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), "");
|
||||
@ -249,10 +275,10 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
|
||||
String strRegexMaxFee = r'max_fee="([0-9\.]+)"';
|
||||
if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) {
|
||||
String strMaxFee =
|
||||
defaultRegex(strRegexMaxFee).firstMatch(newSum).group(1) ?? "0";
|
||||
defaultRegex(strRegexMaxFee).firstMatch(newSum)!.group(1) ?? "0";
|
||||
double doubleMaxFee = double.parse(strMaxFee);
|
||||
|
||||
if (calPercentage > doubleMaxFee) {
|
||||
if (calPercentage! > doubleMaxFee) {
|
||||
return "(" + doubleMaxFee.toString() + ")";
|
||||
}
|
||||
newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), "");
|
||||
@ -273,13 +299,13 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
|
||||
return strCal(sum: sum);
|
||||
}
|
||||
|
||||
Future<double> workoutShippingClassCostWC(
|
||||
{@required String sum, List<CartLineItem> cartLineItem}) async {
|
||||
Future<double?> workoutShippingClassCostWC(
|
||||
{required String? sum, List<CartLineItem>? cartLineItem}) async {
|
||||
if (sum == null || sum == "") {
|
||||
return 0;
|
||||
}
|
||||
sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) {
|
||||
return cartLineItem
|
||||
return cartLineItem!
|
||||
.map((f) => f.quantity)
|
||||
.toList()
|
||||
.reduce((i, d) => i + d)
|
||||
@ -292,27 +318,27 @@ Future<double> workoutShippingClassCostWC(
|
||||
if (replace.groupCount < 1) {
|
||||
return "()";
|
||||
}
|
||||
String newSum = replace.group(1);
|
||||
String newSum = replace.group(1)!;
|
||||
|
||||
// PERCENT
|
||||
String percentVal = newSum.replaceAllMapped(
|
||||
defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) {
|
||||
if (replacePercent != null && replacePercent.groupCount >= 1) {
|
||||
if (replacePercent.groupCount >= 1) {
|
||||
String strPercentage = "( (" +
|
||||
orderTotal.toString() +
|
||||
" * " +
|
||||
replacePercent.group(1).toString() +
|
||||
") / 100 )";
|
||||
double calPercentage = strCal(sum: strPercentage);
|
||||
double? calPercentage = strCal(sum: strPercentage);
|
||||
|
||||
// MIN
|
||||
String strRegexMinFee = r'min_fee="([0-9\.]+)"';
|
||||
if (defaultRegex(strRegexMinFee).hasMatch(newSum)) {
|
||||
String strMinFee =
|
||||
defaultRegex(strRegexMinFee).firstMatch(newSum).group(1) ?? "0";
|
||||
defaultRegex(strRegexMinFee).firstMatch(newSum)!.group(1) ?? "0";
|
||||
double doubleMinFee = double.parse(strMinFee);
|
||||
|
||||
if (calPercentage < doubleMinFee) {
|
||||
if (calPercentage! < doubleMinFee) {
|
||||
return "(" + doubleMinFee.toString() + ")";
|
||||
}
|
||||
newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), "");
|
||||
@ -322,10 +348,10 @@ Future<double> workoutShippingClassCostWC(
|
||||
String strRegexMaxFee = r'max_fee="([0-9\.]+)"';
|
||||
if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) {
|
||||
String strMaxFee =
|
||||
defaultRegex(strRegexMaxFee).firstMatch(newSum).group(1) ?? "0";
|
||||
defaultRegex(strRegexMaxFee).firstMatch(newSum)!.group(1) ?? "0";
|
||||
double doubleMaxFee = double.parse(strMaxFee);
|
||||
|
||||
if (calPercentage > doubleMaxFee) {
|
||||
if (calPercentage! > doubleMaxFee) {
|
||||
return "(" + doubleMaxFee.toString() + ")";
|
||||
}
|
||||
newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), "");
|
||||
@ -348,7 +374,7 @@ Future<double> workoutShippingClassCostWC(
|
||||
|
||||
RegExp defaultRegex(
|
||||
String pattern, {
|
||||
bool strict,
|
||||
bool? strict,
|
||||
}) {
|
||||
return RegExp(
|
||||
pattern,
|
||||
@ -365,10 +391,10 @@ bool isEmail(String em) {
|
||||
}
|
||||
|
||||
navigatorPush(BuildContext context,
|
||||
{@required String routeName,
|
||||
Object arguments,
|
||||
{required String routeName,
|
||||
Object? arguments,
|
||||
bool forgetAll = false,
|
||||
int forgetLast}) {
|
||||
int? forgetLast}) {
|
||||
if (forgetAll) {
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
routeName, (Route<dynamic> route) => false,
|
||||
@ -383,51 +409,11 @@ navigatorPush(BuildContext context,
|
||||
Navigator.of(context).pushNamed(routeName, arguments: arguments);
|
||||
}
|
||||
|
||||
PlatformDialogAction dialogAction(BuildContext context,
|
||||
{@required title, ActionType actionType, Function() action}) {
|
||||
return PlatformDialogAction(
|
||||
actionType: actionType ?? ActionType.Default,
|
||||
child: Text(title ?? ""),
|
||||
onPressed: action ??
|
||||
() {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
showPlatformAlertDialog(BuildContext context,
|
||||
{String title,
|
||||
String subtitle,
|
||||
List<PlatformDialogAction> actions,
|
||||
bool showDoneAction = true}) {
|
||||
if (showDoneAction) {
|
||||
actions.add(dialogAction(context, title: trans("Done"), action: () {
|
||||
Navigator.of(context).pop();
|
||||
}));
|
||||
}
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return PlatformAlertDialog(
|
||||
title: Text(title ?? ""),
|
||||
content: SingleChildScrollView(
|
||||
child: ListBody(
|
||||
children: <Widget>[
|
||||
Text(subtitle ?? ""),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: actions,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
DateTime parseDateTime(String strDate) => DateTime.parse(strDate);
|
||||
|
||||
DateFormat formatDateTime(String format) => DateFormat(format);
|
||||
|
||||
String dateFormatted({@required String date, @required String formatType}) =>
|
||||
String dateFormatted({required String date, required String formatType}) =>
|
||||
formatDateTime(formatType).format(parseDateTime(date));
|
||||
|
||||
enum FormatType {
|
||||
@ -457,20 +443,20 @@ String formatForDateTime(FormatType formatType) {
|
||||
}
|
||||
}
|
||||
|
||||
double parseWcPrice(String price) => (double.tryParse(price ?? "0") ?? 0);
|
||||
double parseWcPrice(String? price) => (double.tryParse(price ?? "0") ?? 0);
|
||||
|
||||
Widget refreshableScroll(context,
|
||||
{@required refreshController,
|
||||
@required VoidCallback onRefresh,
|
||||
@required VoidCallback onLoading,
|
||||
@required List<Product> products,
|
||||
@required onTap,
|
||||
{required refreshController,
|
||||
required VoidCallback onRefresh,
|
||||
required VoidCallback onLoading,
|
||||
required List<Product> products,
|
||||
required onTap,
|
||||
key}) {
|
||||
return SmartRefresher(
|
||||
enablePullDown: true,
|
||||
enablePullUp: true,
|
||||
footer: CustomFooter(
|
||||
builder: (BuildContext context, LoadStatus mode) {
|
||||
builder: (BuildContext context, LoadStatus? mode) {
|
||||
Widget body;
|
||||
if (mode == LoadStatus.idle) {
|
||||
body = Text(trans("pull up load"));
|
||||
@ -492,24 +478,24 @@ Widget refreshableScroll(context,
|
||||
controller: refreshController,
|
||||
onRefresh: onRefresh,
|
||||
onLoading: onLoading,
|
||||
child: (products.length != null && products.isNotEmpty
|
||||
? StaggeredGridView.countBuilder(
|
||||
child: products.isEmpty
|
||||
? NoResultsForProductsWidget()
|
||||
: StaggeredGrid.count(
|
||||
crossAxisCount: 2,
|
||||
itemCount: products.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return Container(
|
||||
height: 200,
|
||||
child: ProductItemContainer(
|
||||
product: products[index],
|
||||
onTap: onTap,
|
||||
),
|
||||
);
|
||||
},
|
||||
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
|
||||
mainAxisSpacing: 4.0,
|
||||
crossAxisSpacing: 4.0,
|
||||
)
|
||||
: NoResultsForProductsWidget()),
|
||||
children: products.map((product) {
|
||||
return StaggeredGridTile.fit(
|
||||
crossAxisCellCount: 1,
|
||||
child: Container(
|
||||
height: 350,
|
||||
child: ProductItemContainer(
|
||||
product: product,
|
||||
onTap: onTap,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList()),
|
||||
);
|
||||
}
|
||||
|
||||
@ -520,9 +506,9 @@ class UserAuth {
|
||||
String redirect = "/home";
|
||||
}
|
||||
|
||||
Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async {
|
||||
String data = await DefaultAssetBundle.of(context)
|
||||
.loadString("public/assets/json/default_shipping.json");
|
||||
Future<List<DefaultShipping>> getDefaultShipping() async {
|
||||
String data =
|
||||
await rootBundle.loadString('public/assets/json/default_shipping.json');
|
||||
dynamic dataJson = json.decode(data);
|
||||
List<DefaultShipping> shipping = [];
|
||||
|
||||
@ -540,44 +526,157 @@ Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async {
|
||||
return shipping;
|
||||
}
|
||||
|
||||
Future<DefaultShipping?> findCountryMetaForShipping(String countryCode) async {
|
||||
List<DefaultShipping> defaultShipping = await getDefaultShipping();
|
||||
List<DefaultShipping> shippingByCountryCode =
|
||||
defaultShipping.where((element) => element.code == countryCode).toList();
|
||||
if (shippingByCountryCode.isNotEmpty) {
|
||||
return shippingByCountryCode.first;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
DefaultShippingState? findDefaultShippingStateByCode(
|
||||
DefaultShipping defaultShipping, String code) {
|
||||
List<DefaultShippingState> defaultShippingStates =
|
||||
defaultShipping.states.where((state) => state.code == code).toList();
|
||||
if (defaultShippingStates.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
DefaultShippingState defaultShippingState = defaultShippingStates.first;
|
||||
return DefaultShippingState(
|
||||
code: defaultShippingState.code, name: defaultShippingState.name);
|
||||
}
|
||||
|
||||
bool hasKeyInMeta(WPUserInfoResponse wpUserInfoResponse, String key) {
|
||||
return (wpUserInfoResponse.data!.metaData ?? [])
|
||||
.where((meta) => meta.key == key)
|
||||
.toList()
|
||||
.isNotEmpty;
|
||||
}
|
||||
|
||||
String fetchValueInMeta(WPUserInfoResponse wpUserInfoResponse, String key) {
|
||||
String value = "";
|
||||
List<dynamic>? metaDataValue = (wpUserInfoResponse.data!.metaData ?? [])
|
||||
.where((meta) => meta.key == key)
|
||||
.first
|
||||
.value;
|
||||
if (metaDataValue != null && metaDataValue.isNotEmpty) {
|
||||
return metaDataValue.first ?? "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
String truncateString(String data, int length) {
|
||||
return (data.length >= length) ? '${data.substring(0, length)}...' : data;
|
||||
}
|
||||
|
||||
Future<List<dynamic>> getWishlistProducts() async {
|
||||
List<dynamic> favouriteProducts = [];
|
||||
String currentProductsJSON = await NyStorage.read(SharedKey.wishlistProducts);
|
||||
String? currentProductsJSON =
|
||||
await (NyStorage.read(SharedKey.wishlistProducts));
|
||||
if (currentProductsJSON != null) {
|
||||
favouriteProducts =
|
||||
(jsonDecode(currentProductsJSON) as List<dynamic>).toList();
|
||||
favouriteProducts = (jsonDecode(currentProductsJSON)).toList();
|
||||
}
|
||||
return favouriteProducts;
|
||||
}
|
||||
|
||||
hasAddedWishlistProduct(int productId) async {
|
||||
hasAddedWishlistProduct(int? productId) async {
|
||||
List<dynamic> favouriteProducts = await getWishlistProducts();
|
||||
List<int> productIds =
|
||||
favouriteProducts.map((e) => e['id']).cast<int>().toList();
|
||||
favouriteProducts.map((e) => e['id']).cast<int>().toList();
|
||||
if (productIds.isEmpty) {
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return productIds.contains(productId);
|
||||
}
|
||||
|
||||
saveWishlistProduct({@required Product product}) async {
|
||||
saveWishlistProduct({required Product? product}) async {
|
||||
List<dynamic> products = await getWishlistProducts();
|
||||
if (products.any((wishListProduct) => wishListProduct['id'] == product.id) ==
|
||||
if (products.any((wishListProduct) => wishListProduct['id'] == product!.id) ==
|
||||
false) {
|
||||
products.add({"id": product.id});
|
||||
products.add({"id": product!.id});
|
||||
}
|
||||
String json = jsonEncode(products.map((i) => {"id": i['id']}).toList());
|
||||
await NyStorage.store(SharedKey.wishlistProducts, json);
|
||||
}
|
||||
|
||||
removeWishlistProduct({@required Product product}) async {
|
||||
removeWishlistProduct({required Product? product}) async {
|
||||
List<dynamic> products = await getWishlistProducts();
|
||||
products.removeWhere((element) => element['id'] == product.id);
|
||||
products.removeWhere((element) => element['id'] == product!.id);
|
||||
|
||||
String json = jsonEncode(products.map((i) => {"id": i['id']}).toList());
|
||||
await NyStorage.store(SharedKey.wishlistProducts, json);
|
||||
}
|
||||
|
||||
Future<BillingDetails> billingDetailsFromWpUserInfoResponse(
|
||||
wpUserInfoResponse) async {
|
||||
List<String> metaDataAddress = [
|
||||
'billing_first_name',
|
||||
'billing_last_name',
|
||||
'billing_company',
|
||||
'billing_address_1',
|
||||
'billing_address_2',
|
||||
'billing_city',
|
||||
'billing_postcode',
|
||||
'billing_country',
|
||||
'billing_state',
|
||||
'billing_phone',
|
||||
'billing_email',
|
||||
'shipping_first_name',
|
||||
'shipping_last_name',
|
||||
'shipping_company',
|
||||
'shipping_address_1',
|
||||
'shipping_address_2',
|
||||
'shipping_city',
|
||||
'shipping_postcode',
|
||||
'shipping_country',
|
||||
'shipping_state',
|
||||
'shipping_phone',
|
||||
];
|
||||
|
||||
Map<String, String> metaData = {};
|
||||
|
||||
for (var dataKey in metaDataAddress) {
|
||||
if (hasKeyInMeta(wpUserInfoResponse, dataKey)) {
|
||||
String value = fetchValueInMeta(wpUserInfoResponse, dataKey);
|
||||
metaData.addAll({dataKey: value});
|
||||
}
|
||||
}
|
||||
|
||||
BillingDetails billingDetails = BillingDetails();
|
||||
await billingDetails.fromWpMeta(metaData);
|
||||
return billingDetails;
|
||||
}
|
||||
|
||||
/// API helper
|
||||
api<T>(dynamic Function(T) request, {BuildContext? context}) async =>
|
||||
await nyApi<T>(
|
||||
request: request, apiDecoders: apiDecoders, context: context);
|
||||
|
||||
/// Event helper
|
||||
event<T>({Map? data}) async => nyEvent<T>(params: data, events: events);
|
||||
|
||||
/// Check if the [Product] is new.
|
||||
bool isProductNew(Product? product) {
|
||||
if (product?.dateCreatedGMT == null) false;
|
||||
try {
|
||||
DateTime dateTime = DateTime.parse(product!.dateCreatedGMT!);
|
||||
return dateTime.isBetween(DateTime.now().subtract(Duration(days: 2)), DateTime.now()) ?? false;
|
||||
} on Exception catch (e) {
|
||||
NyLogger.error(e.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool shouldEncrypt() {
|
||||
String? encryptKey = getEnv('ENCRYPT_KEY', defaultValue: "");
|
||||
if (encryptKey == null || encryptKey == "") {
|
||||
return false;
|
||||
}
|
||||
String? encryptSecret = getEnv('ENCRYPT_KEY', defaultValue: "");
|
||||
if (encryptSecret == null || encryptSecret == "") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
@ -12,13 +12,13 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/app/models/cart.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
|
||||
import 'package:nylo_support/helpers/helper.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
Future<bool> authCheck() async => ((await getUser()) != null);
|
||||
|
||||
Future<String> readAuthToken() async => (await getUser()).token;
|
||||
Future<String?> readAuthToken() async => (await getUser())!.token;
|
||||
|
||||
Future<String> readUserId() async => (await getUser()).userId;
|
||||
Future<String?> readUserId() async => (await getUser())!.userId;
|
||||
|
||||
authLogout(BuildContext context) async {
|
||||
await NyStorage.delete(SharedKey.authUser);
|
||||
|
||||
@ -18,7 +18,7 @@ import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const SymbolPositionType app_currency_symbol_position = SymbolPositionType.left;
|
||||
const SymbolPositionType appCurrencySymbolPosition = SymbolPositionType.left;
|
||||
// currency_symbol_position example.
|
||||
// left: $15
|
||||
// right: 15€
|
||||
33
LabelStoreMax/lib/config/decoders.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'package:flutter_app/app/models/user.dart';
|
||||
import 'package:flutter_app/app/networking/api_service.dart';
|
||||
import 'package:flutter_app/app/networking/dio/base_api_service.dart';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Model Decoders
|
||||
| -------------------------------------------------------------------------
|
||||
| Model decoders are used in 'app/networking/' for morphing json payloads
|
||||
| into Models. Learn more https://nylo.dev/docs/5.x/decoders#model-decoders
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
final Map<Type, dynamic> modelDecoders = {
|
||||
// ...
|
||||
User: (data) => User.fromJson(data)
|
||||
};
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Decoders
|
||||
| -------------------------------------------------------------------------
|
||||
| API decoders are used when you need to access an API service using the
|
||||
| 'api' helper. E.g. api<MyApiService>((request) => request.fetchData());
|
||||
| Learn more https://nylo.dev/docs/5.x/decoders#api-decoders
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
final Map<Type, BaseApiService> apiDecoders = {
|
||||
ApiService: ApiService(),
|
||||
|
||||
// ...
|
||||
};
|
||||
32
LabelStoreMax/lib/config/design.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_app/config/toast_notification.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/toast_notification_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Design
|
||||
| Contains widgets used in the Nylo framework.
|
||||
|
|
||||
| Learn more: https://nylo.dev/docs/5.x/themes
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Widget logo = StoreLogo();
|
||||
// resources/widgets/woosignal_ui.dart
|
||||
|
||||
Widget loader = AppLoaderWidget();
|
||||
// resources/widgets/app_loader_widget.dart
|
||||
|
||||
Widget getToastNotificationWidget({
|
||||
required ToastNotificationStyleType style,
|
||||
Function(ToastNotificationStyleMetaHelper helper)? toastNotificationStyleMeta, Function? onDismiss}) {
|
||||
if (toastNotificationStyleMeta == null) return SizedBox.shrink();
|
||||
|
||||
ToastMeta toastMeta = toastNotificationStyleMeta(NyToastNotificationStyleMetaHelper(style));
|
||||
|
||||
return ToastNotification(toastMeta, onDismiss: onDismiss);
|
||||
// resources/widgets/toast_notification.dart
|
||||
}
|
||||
19
LabelStoreMax/lib/config/events.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:flutter_app/app/events/login_event.dart';
|
||||
import 'package:flutter_app/app/events/logout_event.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Events
|
||||
| Add your "app/events" here.
|
||||
| Events can be fired using: event<MyEvent>();
|
||||
|
|
||||
| Learn more: https://nylo.dev/docs/5.x/events
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
final Map<Type, NyEvent> events = {
|
||||
LoginEvent: LoginEvent(),
|
||||
LogoutEvent: LogoutEvent(),
|
||||
AuthUserEvent: AuthUserEvent(),
|
||||
};
|
||||
@ -18,7 +18,7 @@ final LocaleType localeType = LocaleType.asDefined; // device, asDefined
|
||||
| The language code should match the name of the file i.e /lang/es.json
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
final String languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en");
|
||||
final String? languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en");
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -1,8 +1,10 @@
|
||||
import 'package:flutter_app/app/models/payment_type.dart';
|
||||
import 'package:flutter_app/app/providers/cash_on_delivery.dart';
|
||||
import 'package:flutter_app/app/providers/paypal_pay.dart';
|
||||
import 'package:flutter_app/app/providers/stripe_pay.dart';
|
||||
import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart';
|
||||
import 'package:flutter_app/app/providers/payments/paypal_pay.dart';
|
||||
import 'package:flutter_app/app/providers/payments/razorpay_pay.dart';
|
||||
import 'package:flutter_app/app/providers/payments/stripe_pay.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -13,15 +15,15 @@ import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const app_payment_gateways = [];
|
||||
// Available: "Stripe", "CashOnDelivery", "PayPal"
|
||||
const appPaymentGateways = ["CashOnDelivery"];
|
||||
// Available: "Stripe", "CashOnDelivery", "PayPal", "RazorPay"
|
||||
// e.g. app_payment_gateways = ["Stripe", "CashOnDelivery"]; will only use Stripe and Cash on Delivery.
|
||||
|
||||
List<PaymentType> paymentTypeList = [
|
||||
addPayment(
|
||||
id: 1,
|
||||
name: "Stripe",
|
||||
desc: "Debit or Credit Card",
|
||||
description: trans("Debit or Credit Card"),
|
||||
assetImage: "dark_powered_by_stripe.png",
|
||||
pay: stripePay,
|
||||
),
|
||||
@ -29,7 +31,7 @@ List<PaymentType> paymentTypeList = [
|
||||
addPayment(
|
||||
id: 2,
|
||||
name: "CashOnDelivery",
|
||||
desc: "Cash on delivery",
|
||||
description: trans("Cash on delivery"),
|
||||
assetImage: "cash_on_delivery.jpeg",
|
||||
pay: cashOnDeliveryPay,
|
||||
),
|
||||
@ -37,17 +39,25 @@ List<PaymentType> paymentTypeList = [
|
||||
addPayment(
|
||||
id: 4,
|
||||
name: "PayPal",
|
||||
desc: "Debit or Credit Card",
|
||||
description: trans("Debit or Credit Card"),
|
||||
assetImage: "paypal_logo.png",
|
||||
pay: payPalPay,
|
||||
),
|
||||
|
||||
addPayment(
|
||||
id: 5,
|
||||
name: "RazorPay",
|
||||
description: trans("Debit or Credit Card"),
|
||||
assetImage: "razorpay.png",
|
||||
pay: razorPay,
|
||||
),
|
||||
|
||||
// e.g. add more here
|
||||
|
||||
// addPayment(
|
||||
// id: 5,
|
||||
// id: 6,
|
||||
// name: "MyNewPaymentMethod",
|
||||
// desc: "Debit or Credit Card",
|
||||
// description: "Debit or Credit Card",
|
||||
// assetImage: "add icon image to public/assets/images/myimage.png",
|
||||
// pay: "myCustomPaymentFunction",
|
||||
// ),
|
||||
24
LabelStoreMax/lib/config/providers.dart
Normal file
@ -0,0 +1,24 @@
|
||||
import '/app/providers/firebase_provider.dart';
|
||||
import 'package:flutter_app/app/providers/app_provider.dart';
|
||||
import 'package:flutter_app/app/providers/event_provider.dart';
|
||||
import 'package:flutter_app/app/providers/route_provider.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Providers
|
||||
| Add your "app/providers" here.
|
||||
| Providers are booted when your application start.
|
||||
|
|
||||
| Learn more: https://nylo.dev/docs/5.x/providers
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
final Map<Type, NyProvider> providers = {
|
||||
AppProvider: AppProvider(),
|
||||
RouteProvider: RouteProvider(),
|
||||
EventProvider: EventProvider(),
|
||||
FirebaseProvider: FirebaseProvider(),
|
||||
|
||||
};
|
||||
|
||||
19
LabelStoreMax/lib/config/storage_keys.dart
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Storage Keys
|
||||
| Add your storage keys here and then use them later to retrieve data.
|
||||
| E.g. static String userCoins = "USER_COINS";
|
||||
| String coins = NyStorage.read( StorageKey.userCoins );
|
||||
|
|
||||
| Learn more: https://nylo.dev/docs/5.x/storage#storage-keys
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
class StorageKey {
|
||||
static String userToken = "USER_TOKEN";
|
||||
static String authUser = getEnv('AUTH_USER_KEY', defaultValue: 'AUTH_USER');
|
||||
|
||||
/// Add your storage keys here...
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
import 'package:flutter_app/bootstrap/base_theme_config.dart';
|
||||
import 'package:flutter_app/resources/themes/dark_theme.dart';
|
||||
import 'package:flutter_app/resources/themes/light_theme.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/color_styles.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/dark_theme_colors.dart';
|
||||
import 'package:flutter_app/resources/themes/styles/light_theme_colors.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -12,7 +12,7 @@ import 'package:flutter_app/resources/themes/styles/light_theme_colors.dart';
|
||||
*/
|
||||
|
||||
// App Themes
|
||||
final appThemes = [
|
||||
final List<BaseThemeConfig<ColorStyles>> appThemes = [
|
||||
ThemeConfig.light(),
|
||||
ThemeConfig.dark(),
|
||||
];
|
||||
@ -24,10 +24,10 @@ final appThemes = [
|
||||
*/
|
||||
|
||||
// Light Colors
|
||||
BaseColorStyles lightColors = LightThemeColors();
|
||||
ColorStyles lightColors = LightThemeColors();
|
||||
|
||||
// Dark Colors
|
||||
BaseColorStyles darkColors = DarkThemeColors();
|
||||
ColorStyles darkColors = DarkThemeColors();
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -38,7 +38,7 @@ BaseColorStyles darkColors = DarkThemeColors();
|
||||
// Preset Themes
|
||||
class ThemeConfig {
|
||||
// LIGHT
|
||||
static BaseThemeConfig light() => BaseThemeConfig(
|
||||
static BaseThemeConfig<ColorStyles> light() => BaseThemeConfig<ColorStyles>(
|
||||
id: "default_light_theme",
|
||||
description: "Light theme",
|
||||
theme: lightTheme(lightColors),
|
||||
@ -46,7 +46,7 @@ class ThemeConfig {
|
||||
);
|
||||
|
||||
// DARK
|
||||
static BaseThemeConfig dark() => BaseThemeConfig(
|
||||
static BaseThemeConfig<ColorStyles> dark() => BaseThemeConfig<ColorStyles>(
|
||||
id: "default_dark_theme",
|
||||
description: "Dark theme",
|
||||
theme: darkTheme(darkColors),
|
||||
@ -60,10 +60,10 @@ class ThemeConfig {
|
||||
|
||||
// First add the colors which was created into the above section like the following:
|
||||
// Bright Colors
|
||||
/// BaseColorStyles brightColors = BrightThemeColors();
|
||||
/// ColorStyles brightColors = BrightThemeColors();
|
||||
|
||||
// Next, uncomment the below:
|
||||
/// static BaseThemeConfig bright() => BaseThemeConfig(
|
||||
/// static BaseThemeConfig<ColorStyles> bright() => BaseThemeConfig<ColorStyles>(
|
||||
/// id: "default_bright_theme",
|
||||
/// description: "Bright theme",
|
||||
/// theme: brightTheme(brightColors),
|
||||
34
LabelStoreMax/lib/config/toast_notification.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
/// ToastNotificationStyleMetaHelper is used to return
|
||||
/// the correct value for the [ToastNotificationStyleType] toast style.
|
||||
class NyToastNotificationStyleMetaHelper extends ToastNotificationStyleMetaHelper {
|
||||
|
||||
NyToastNotificationStyleMetaHelper(ToastNotificationStyleType? style) : super(style);
|
||||
|
||||
onSuccess() {
|
||||
return ToastMeta.success();
|
||||
}
|
||||
|
||||
onWarning() {
|
||||
return ToastMeta.warning();
|
||||
}
|
||||
|
||||
onInfo() {
|
||||
return ToastMeta.info();
|
||||
}
|
||||
|
||||
onDanger() {
|
||||
return ToastMeta.danger();
|
||||
}
|
||||
|
||||
// Example customizing a notification
|
||||
// onSuccess() {
|
||||
// return ToastMeta.success(
|
||||
// title: "Hello",
|
||||
// description: "World",
|
||||
// action: () {},
|
||||
// backgroundColor: Colors.Yellow
|
||||
// );
|
||||
// }
|
||||
}
|
||||
36
LabelStoreMax/lib/config/validation_rules.dart
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Rules
|
||||
| -------------------------------------------------------------------------
|
||||
| Add custom validation rules for your project in this file.
|
||||
| Learn more https://nylo.dev/docs/5.x/validation#custom-validation-rules
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
final Map<String, dynamic> validationRules = {
|
||||
/// Example
|
||||
// "simple_password": (attribute) => SimplePassword(attribute)
|
||||
};
|
||||
|
||||
/// Example validation class
|
||||
// class SimplePassword extends ValidationRule {
|
||||
// SimplePassword(String attribute)
|
||||
// : super(
|
||||
// attribute: attribute,
|
||||
// signature: "simple_password", // Use this signature for the validator
|
||||
// description: "The $attribute field must be between 4 and 8 digits long and include at least one numeric digit", // Toast description when an error occurs
|
||||
// textFieldMessage: "Must be between 4 and 8 digits long with one numeric digit"); // TextField description when an error occurs
|
||||
//
|
||||
// @override
|
||||
// handle(Map<String, dynamic> info) {
|
||||
// super.handle(info);
|
||||
//
|
||||
// /// info['rule'] = Validation rule i.e "min".
|
||||
// /// info['data'] = Data the user has passed into the validation.
|
||||
// /// info['message'] = Overriding message to be displayed for validation (optional).
|
||||
//
|
||||
// RegExp regExp = RegExp(r'^(?=.*\d).{4,8}$');
|
||||
// return regExp.hasMatch(info['data']);
|
||||
// }
|
||||
// }
|
||||
66
LabelStoreMax/lib/firebase_options.dart
Normal file
@ -0,0 +1,66 @@
|
||||
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for web - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
if (AppHelper.instance.appConfig?.firebaseOptionsAndroid == null) {
|
||||
throw UnsupportedError(
|
||||
'Add a valid Firebase json config on https://woosignal.com for your WooCommerce store',
|
||||
);
|
||||
}
|
||||
return FirebaseOptions(
|
||||
apiKey: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['apiKey'],
|
||||
appId: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['appId'],
|
||||
messagingSenderId: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['messagingSenderId'],
|
||||
projectId: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['projectId'],
|
||||
storageBucket: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['storageBucket'],
|
||||
);
|
||||
case TargetPlatform.iOS:
|
||||
if (AppHelper.instance.appConfig?.firebaseOptionsIos == null) {
|
||||
throw UnsupportedError(
|
||||
'Add a valid Firebase plist config on https://woosignal.com for your WooCommerce store',
|
||||
);
|
||||
}
|
||||
return FirebaseOptions(
|
||||
apiKey: AppHelper.instance.appConfig!.firebaseOptionsIos!['apiKey'],
|
||||
appId: AppHelper.instance.appConfig!.firebaseOptionsIos!['appId'],
|
||||
messagingSenderId: AppHelper.instance.appConfig!.firebaseOptionsIos!['messagingSenderId'],
|
||||
projectId: AppHelper.instance.appConfig!.firebaseOptionsIos!['projectId'],
|
||||
storageBucket: AppHelper.instance.appConfig!.firebaseOptionsIos!['storageBucket'],
|
||||
iosClientId: AppHelper.instance.appConfig!.firebaseOptionsIos!['iosClientId'],
|
||||
iosBundleId: AppHelper.instance.appConfig!.firebaseOptionsIos!['iosBundleId'],
|
||||
);
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// ignore_for_file: directives_ordering
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
import 'package:flutter_secure_storage_web/flutter_secure_storage_web.dart';
|
||||
import 'package:shared_preferences_web/shared_preferences_web.dart';
|
||||
import 'package:url_launcher_web/url_launcher_web.dart';
|
||||
|
||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||
|
||||
// ignore: public_member_api_docs
|
||||
void registerPlugins(Registrar registrar) {
|
||||
FlutterSecureStorageWeb.registerWith(registrar);
|
||||
SharedPreferencesPlugin.registerWith(registrar);
|
||||
UrlLauncherPlugin.registerWith(registrar);
|
||||
registrar.registerMessageHandler();
|
||||
}
|
||||
@ -1,24 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/app.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/boot.dart';
|
||||
import 'package:flutter_app/routes/router.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
Nylo nylo = await Nylo.init(router: appRouter(), setup: boot);
|
||||
|
||||
String initialRoute = AppHelper.instance.appConfig.appStatus != null
|
||||
? '/home'
|
||||
: '/no-connection';
|
||||
Nylo nylo = await Nylo.init(setup: Boot.nylo, setupFinished: Boot.finished);
|
||||
|
||||
runApp(
|
||||
AppBuild(
|
||||
navigatorKey: nylo.router.navigatorKey,
|
||||
onGenerateRoute: nylo.router.generator(),
|
||||
initialRoute: initialRoute,
|
||||
navigatorKey: NyNavigator.instance.router.navigatorKey,
|
||||
onGenerateRoute: nylo.router!.generator(),
|
||||
initialRoute: nylo.getInitialRoute(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,234 +0,0 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:wp_json_api/models/responses/wc_customer_info_response.dart';
|
||||
import 'package:wp_json_api/models/responses/wc_customer_updated_response.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
class AccountBillingDetailsPage extends StatefulWidget {
|
||||
AccountBillingDetailsPage();
|
||||
|
||||
@override
|
||||
_AccountBillingDetailsPageState createState() =>
|
||||
_AccountBillingDetailsPageState();
|
||||
}
|
||||
|
||||
class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
|
||||
_AccountBillingDetailsPageState();
|
||||
|
||||
// BILLING TEXT CONTROLLERS
|
||||
final TextEditingController _txtShippingFirstName = TextEditingController(),
|
||||
_txtShippingLastName = TextEditingController(),
|
||||
_txtShippingAddressLine = TextEditingController(),
|
||||
_txtShippingCity = TextEditingController(),
|
||||
_txtShippingState = TextEditingController(),
|
||||
_txtShippingPostalCode = TextEditingController(),
|
||||
_txtShippingCountry = TextEditingController();
|
||||
|
||||
bool _isLoading = true, _isUpdating = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fetchUserDetails();
|
||||
}
|
||||
|
||||
_fetchUserDetails() async {
|
||||
WCCustomerInfoResponse wcCustomerInfoResponse =
|
||||
await WPJsonAPI.instance.api((request) async {
|
||||
return request.wcCustomerInfo(await readAuthToken());
|
||||
});
|
||||
|
||||
Billing billing = wcCustomerInfoResponse.data.billing;
|
||||
_txtShippingFirstName.text = billing.firstName;
|
||||
_txtShippingLastName.text = billing.lastName;
|
||||
|
||||
_txtShippingAddressLine.text = billing.address1;
|
||||
_txtShippingCity.text = billing.city;
|
||||
_txtShippingState.text = billing.state;
|
||||
_txtShippingPostalCode.text = billing.postcode;
|
||||
_txtShippingCountry.text = billing.country;
|
||||
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: Text(trans("Billing Details")),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||
child: _isLoading
|
||||
? AppLoaderWidget()
|
||||
: LayoutBuilder(
|
||||
builder: (context, constraints) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("First Name"),
|
||||
controller: _txtShippingFirstName,
|
||||
shouldAutoFocus: true,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Last Name"),
|
||||
controller: _txtShippingLastName,
|
||||
),
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
),
|
||||
TextEditingRow(
|
||||
heading: trans("Address Line"),
|
||||
controller: _txtShippingAddressLine,
|
||||
),
|
||||
Row(children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("City"),
|
||||
controller: _txtShippingCity,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("State"),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: _txtShippingState),
|
||||
),
|
||||
]),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Postal code"),
|
||||
controller: _txtShippingPostalCode,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Country"),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: _txtShippingCountry,
|
||||
),
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
)
|
||||
],
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: ThemeColor.get(context).surfaceBackground,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? wsBoxShadow()
|
||||
: null,
|
||||
),
|
||||
padding: EdgeInsets.all(8),
|
||||
),
|
||||
height:
|
||||
(constraints.maxHeight - constraints.minHeight) *
|
||||
0.6,
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
PrimaryButton(
|
||||
title: trans("UPDATE DETAILS"),
|
||||
isLoading: _isUpdating,
|
||||
action: _updateBillingDetails,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_updateBillingDetails() async {
|
||||
String firstName = _txtShippingFirstName.text;
|
||||
String lastName = _txtShippingLastName.text;
|
||||
String addressLine = _txtShippingAddressLine.text;
|
||||
String city = _txtShippingCity.text;
|
||||
String state = _txtShippingState.text;
|
||||
String postalCode = _txtShippingPostalCode.text;
|
||||
String country = _txtShippingCountry.text;
|
||||
|
||||
String userToken = await readAuthToken();
|
||||
|
||||
setState(() {
|
||||
_isUpdating = true;
|
||||
});
|
||||
|
||||
WCCustomerUpdatedResponse wcCustomerUpdatedResponse;
|
||||
try {
|
||||
wcCustomerUpdatedResponse = await WPJsonAPI.instance.api((request) =>
|
||||
request.wcUpdateCustomerInfo(userToken,
|
||||
billingFirstName: firstName,
|
||||
billingLastName: lastName,
|
||||
billingAddress1: addressLine,
|
||||
billingCity: city,
|
||||
billingState: state,
|
||||
billingPostcode: postalCode,
|
||||
billingCountry: country));
|
||||
} on Exception catch (_) {
|
||||
showToastNotification(context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER);
|
||||
} finally {
|
||||
setState(() {
|
||||
_isUpdating = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (wcCustomerUpdatedResponse != null &&
|
||||
wcCustomerUpdatedResponse.status == 200) {
|
||||
showToastNotification(context,
|
||||
title: trans("Success"),
|
||||
description: trans("Account updated"),
|
||||
style: ToastNotificationStyleType.SUCCESS);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
LabelStoreMax/lib/resources/pages/account_delete_page.dart
Normal file
@ -0,0 +1,105 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2023, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:wp_json_api/models/responses/wp_user_delete_response.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
class AccountDeletePage extends StatefulWidget {
|
||||
AccountDeletePage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AccountDeletePageState createState() => _AccountDeletePageState();
|
||||
}
|
||||
|
||||
class _AccountDeletePageState extends NyState<AccountDeletePage> {
|
||||
@override
|
||||
init() async {}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(trans("Delete Account")),
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.no_accounts_rounded, size: 50),
|
||||
Text(
|
||||
trans("Delete your account"),
|
||||
style: textTheme.displaySmall,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 18),
|
||||
child: Text(trans("Are you sure?")),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
PrimaryButton(
|
||||
title: trans("Yes, delete my account"),
|
||||
isLoading: isLocked('delete_account'),
|
||||
action: _deleteAccount,
|
||||
),
|
||||
LinkButton(title: trans("Back"), action: pop)
|
||||
],
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
_deleteAccount() async {
|
||||
await lockRelease('delete_account', perform: () async {
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
WPUserDeleteResponse? wpUserDeleteResponse;
|
||||
try {
|
||||
wpUserDeleteResponse = await WPJsonAPI.instance
|
||||
.api((request) => request.wpUserDelete(userToken));
|
||||
} on Exception catch (e) {
|
||||
NyLogger.error(e.toString());
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER,
|
||||
);
|
||||
}
|
||||
|
||||
if (wpUserDeleteResponse != null) {
|
||||
showToast(
|
||||
title: trans("Success"), description: trans("Account deleted"));
|
||||
await authLogout(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||