diff --git a/LabelStoreMax/CHANGELOG.md b/LabelStoreMax/CHANGELOG.md index e3df2a5..580e4ed 100644 --- a/LabelStoreMax/CHANGELOG.md +++ b/LabelStoreMax/CHANGELOG.md @@ -1,3 +1,9 @@ +## [7.0.0] - 2024-03-26 + +* Refactor project +* New Notifications page +* Pubspec.yaml dependency updates + ## [6.15.0] - 2024-03-08 * Increase minimum ios version to 14.0 diff --git a/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj b/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj index 267c84e..472d848 100644 --- a/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj +++ b/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj @@ -56,6 +56,7 @@ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 8362715010B1DC025B396ED3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 8DD46F1E543D90202726C03D /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 925D64452BA7F98500C41197 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -152,6 +153,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + 925D64452BA7F98500C41197 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -467,7 +469,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -647,7 +651,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -671,7 +677,9 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; diff --git a/LabelStoreMax/ios/Runner/Runner.entitlements b/LabelStoreMax/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/LabelStoreMax/ios/Runner/Runner.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/LabelStoreMax/lang/de.json b/LabelStoreMax/lang/de.json index a5827a7..8833b7f 100644 --- a/LabelStoreMax/lang/de.json +++ b/LabelStoreMax/lang/de.json @@ -237,5 +237,7 @@ "Delete my account": "Mein Konto löschen", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) artikel aus {{appName}}", "Invalid email address": "Ungültige E-Mail-Adresse", - "By completing this order, I agree to all": "Mit Abschluss dieser Bestellung stimme ich allem zu" + "By completing this order, I agree to all": "Mit Abschluss dieser Bestellung stimme ich allem zu", + "Change language": "Sprache ändern", + "Select your language": "Wähle deine Sprache" } \ No newline at end of file diff --git a/LabelStoreMax/lang/en.json b/LabelStoreMax/lang/en.json index d849419..3944b5f 100644 --- a/LabelStoreMax/lang/en.json +++ b/LabelStoreMax/lang/en.json @@ -237,5 +237,7 @@ "({{itemCount}}) items from {{appName}}": "({{itemCount}}) items from {{appName}}", "Contact us for any questions on your order.": "Contact us for any questions on your order.", "Invalid email address": "Invalid email address", - "By completing this order, I agree to all": "By completing this order, I agree to all" + "By completing this order, I agree to all": "By completing this order, I agree to all", + "Change language": "Change language", + "Select your language": "Select your language" } \ No newline at end of file diff --git a/LabelStoreMax/lang/es.json b/LabelStoreMax/lang/es.json index 7a3ff7f..c77d2ed 100644 --- a/LabelStoreMax/lang/es.json +++ b/LabelStoreMax/lang/es.json @@ -237,5 +237,7 @@ "Delete my account": "Borrar mi cuenta", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) items from {{appName}}", "Invalid email address": "Dirección de correo electrónico no válida", - "By completing this order, I agree to all": "Al completar este pedido, acepto todos" + "By completing this order, I agree to all": "Al completar este pedido, acepto todos", + "Change language": "Cambiar idioma", + "Select your language": "elige tu idioma" } \ No newline at end of file diff --git a/LabelStoreMax/lang/fr.json b/LabelStoreMax/lang/fr.json index 1026b08..ebe0bf4 100644 --- a/LabelStoreMax/lang/fr.json +++ b/LabelStoreMax/lang/fr.json @@ -237,5 +237,7 @@ "Delete my account": "Supprimer mon compte", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) articles de {{appName}}", "Invalid email address": "Adresse e-mail invalide", - "By completing this order, I agree to all": "En remplissant cette commande, j'accepte toutes" + "By completing this order, I agree to all": "En remplissant cette commande, j'accepte toutes", + "Change language": "Changer de langue", + "Select your language": "choisissez votre langue" } \ No newline at end of file diff --git a/LabelStoreMax/lang/hi.json b/LabelStoreMax/lang/hi.json index 5285c8d..0b44b3f 100644 --- a/LabelStoreMax/lang/hi.json +++ b/LabelStoreMax/lang/hi.json @@ -237,5 +237,7 @@ "Delete my account": "mera ekaunt hata do", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) se aaitam {{appName}}", "Invalid email address": "amaany eemel pata", - "By completing this order, I agree to all": "is aadesh ko poora karake, main sabhee ke lie sahamat hoon" + "By completing this order, I agree to all": "is aadesh ko poora karake, main sabhee ke lie sahamat hoon", + "Change language": "bhaasha badalen", + "Select your language": "apanee bhaasha ka chayan karen" } \ No newline at end of file diff --git a/LabelStoreMax/lang/id.json b/LabelStoreMax/lang/id.json index b110343..9e3f0c3 100644 --- a/LabelStoreMax/lang/id.json +++ b/LabelStoreMax/lang/id.json @@ -238,4 +238,6 @@ "Contact us for any questions on your order.": "Hubungi kami jika ada pertanyaan tentang pesanan Anda.", "Invalid email address": "alamat email salah", "By completing this order, I agree to all": "Dengan menyelesaikan pesanan ini, saya menyetujui semuanya", + "Change language": "Ganti BAHASA", + "Select your language": "Pilih bahasamu" } \ No newline at end of file diff --git a/LabelStoreMax/lang/it.json b/LabelStoreMax/lang/it.json index f217d49..e46ec8a 100644 --- a/LabelStoreMax/lang/it.json +++ b/LabelStoreMax/lang/it.json @@ -237,5 +237,7 @@ "Delete my account": "Cancella il mio account", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) elementi da {{appName}}", "Invalid email address": "indirizzo email non valido", - "By completing this order, I agree to all": "Completando questo ordine, accetto tutto" + "By completing this order, I agree to all": "Completando questo ordine, accetto tutto", + "Change language": "Cambia lingua", + "Select your language": "seleziona la tua lingua" } \ No newline at end of file diff --git a/LabelStoreMax/lang/nl.json b/LabelStoreMax/lang/nl.json index 06171d2..ef6c486 100644 --- a/LabelStoreMax/lang/nl.json +++ b/LabelStoreMax/lang/nl.json @@ -237,5 +237,7 @@ "Delete my account": "Verwijder mijn account", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) artikelen van {{appName}}", "Invalid email address": "Ongeldig e-mailadres", - "By completing this order, I agree to all": "Door deze bestelling te voltooien, ga ik akkoord met alles" + "By completing this order, I agree to all": "Door deze bestelling te voltooien, ga ik akkoord met alles", + "Change language": "Taal wijzigen", + "Select your language": "Selecteer je taal" } \ No newline at end of file diff --git a/LabelStoreMax/lang/pt.json b/LabelStoreMax/lang/pt.json index 96c0efc..4b243ca 100644 --- a/LabelStoreMax/lang/pt.json +++ b/LabelStoreMax/lang/pt.json @@ -237,5 +237,7 @@ "Contact us for any questions on your order.": "Entre em contato conosco para qualquer dúvida sobre seu pedido.", "Delete my account": "Deletar minha conta", "Invalid email address": "Endereço de email invalido", - "By completing this order, I agree to all": "Ao concluir este pedido, concordo com todos" + "By completing this order, I agree to all": "Ao concluir este pedido, concordo com todos", + "Change language": "Mudar idioma", + "Select your language": "selecione sua lingua" } \ No newline at end of file diff --git a/LabelStoreMax/lang/th.json b/LabelStoreMax/lang/th.json index 2f0a456..2e26562 100644 --- a/LabelStoreMax/lang/th.json +++ b/LabelStoreMax/lang/th.json @@ -238,4 +238,6 @@ "Contact us for any questions on your order.": "ติดต่อเราหากมีคำถามเกี่ยวกับคำสั่งซื้อของคุณ", "Invalid email address": "ที่อยู่อีเมลที่ไม่ถูกต้อง", "By completing this order, I agree to all": "เมื่อดำเนินการตามคำสั่งซื้อนี้เสร็จสิ้น ฉันยอมรับทุกประการ", + "Change language": "เปลี่ยนภาษา", + "Select your language": "เลือกภาษาของคุณ" } \ No newline at end of file diff --git a/LabelStoreMax/lang/tr.json b/LabelStoreMax/lang/tr.json index 1033b35..bbcdfd1 100644 --- a/LabelStoreMax/lang/tr.json +++ b/LabelStoreMax/lang/tr.json @@ -237,5 +237,7 @@ "Delete my account": "Hesabımı sil", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) gelen öğeler {{appName}}", "Invalid email address": "Geçersiz e-posta adresi", - "By completing this order, I agree to all": "Bu siparişi tamamlayarak, tümünü kabul ediyorum" + "By completing this order, I agree to all": "Bu siparişi tamamlayarak, tümünü kabul ediyorum", + "Change language": "Dili değiştir", + "Select your language": "Dilinizi seçiniz" } \ No newline at end of file diff --git a/LabelStoreMax/lang/zh.json b/LabelStoreMax/lang/zh.json index e7fd1cb..c93caba 100644 --- a/LabelStoreMax/lang/zh.json +++ b/LabelStoreMax/lang/zh.json @@ -237,5 +237,7 @@ "Delete my account": "删除我的账户", "({{itemCount}}) items from {{appName}}": "({{itemCount}}) 物品来自 {{appName}}", "Invalid email address": "无效的邮件地址", - "By completing this order, I agree to all": "通过完成此订单,我同意所有" + "By completing this order, I agree to all": "通过完成此订单,我同意所有", + "Change language": "改变语言", + "Select your language": "选择你的语言" } \ No newline at end of file diff --git a/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart b/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart deleted file mode 100644 index 7fb5827..0000000 --- a/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class AccountOrderDetailController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/browse_category_controller.dart b/LabelStoreMax/lib/app/controllers/browse_category_controller.dart deleted file mode 100644 index 021c7db..0000000 --- a/LabelStoreMax/lib/app/controllers/browse_category_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class BrowseCategoryController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/browse_search_controller.dart b/LabelStoreMax/lib/app/controllers/browse_search_controller.dart deleted file mode 100644 index de8a549..0000000 --- a/LabelStoreMax/lib/app/controllers/browse_search_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class BrowseSearchController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart b/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart deleted file mode 100644 index 3029017..0000000 --- a/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class CheckoutStatusController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/controller.dart b/LabelStoreMax/lib/app/controllers/controller.dart index e4e14cd..6919d67 100644 --- a/LabelStoreMax/lib/app/controllers/controller.dart +++ b/LabelStoreMax/lib/app/controllers/controller.dart @@ -11,7 +11,7 @@ import 'package:nylo_framework/nylo_framework.dart'; /// Base Controller for the Nylo -/// See more on controllers here - https://nylo.dev/docs/2.x/controllers +/// See more on controllers here - https://nylo.dev/docs/5.20.0/controllers class Controller extends NyController { Controller(); } diff --git a/LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart b/LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart deleted file mode 100644 index 325c9ab..0000000 --- a/LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/app/controllers/woosignal_api_loader_controller.dart'; -import 'package:woosignal/models/response/order.dart'; - -class CustomerOrdersLoaderController - extends WooSignalApiLoaderController { - CustomerOrdersLoaderController(); - - Future loadOrders( - {required bool Function(bool hasProducts) hasResults, - required void Function() didFinish, - required String userId}) async { - await load( - hasResults: hasResults, - didFinish: didFinish, - apiQuery: (api) => api.getOrders( - customer: int.parse(userId), page: page, perPage: 50)); - } -} diff --git a/LabelStoreMax/lib/app/controllers/leave_review_controller.dart b/LabelStoreMax/lib/app/controllers/leave_review_controller.dart deleted file mode 100644 index 94438ad..0000000 --- a/LabelStoreMax/lib/app/controllers/leave_review_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class LeaveReviewController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart deleted file mode 100644 index b265851..0000000 --- a/LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/app/controllers/woosignal_api_loader_controller.dart'; -import 'package:woosignal/models/response/product_category.dart'; -import 'package:woosignal/models/response/product.dart'; - -class ProductCategorySearchLoaderController - extends WooSignalApiLoaderController { - ProductCategorySearchLoaderController(); - - Future loadProducts( - {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", - ), - ); - } -} diff --git a/LabelStoreMax/lib/app/controllers/product_detail_controller.dart b/LabelStoreMax/lib/app/controllers/product_detail_controller.dart index d6a6cb3..0b13cd8 100644 --- a/LabelStoreMax/lib/app/controllers/product_detail_controller.dart +++ b/LabelStoreMax/lib/app/controllers/product_detail_controller.dart @@ -70,10 +70,8 @@ class ProductDetailController extends Controller { if (onSuccess != null) { onSuccess(); } - updateState(ProductQuantity.state, data: { - "product_id": product?.id, - "quantity": quantity - }); + updateState(ProductQuantity.state, + data: {"product_id": product?.id, "quantity": quantity}); } } @@ -83,10 +81,8 @@ class ProductDetailController extends Controller { if (onSuccess != null) { onSuccess(); } - updateState(ProductQuantity.state, data: { - "product_id": product?.id, - "quantity": quantity - }); + updateState(ProductQuantity.state, + data: {"product_id": product?.id, "quantity": quantity}); } } @@ -134,6 +130,39 @@ class ProductDetailController extends Controller { } } - return tmpProductVariation; + if (tmpProductVariation != null) { + return tmpProductVariation; + } + + // attempt to find product variation + List tmpKeys = []; + for (var productVariation in productVariations) { + for (var attr in productVariation.attributes) { + String? attrName = attr.name; + if (attrName == null) continue; + tmpKeys.add(attrName); + } + } + + // Find matching product variation + tmpSelectedObj.removeWhere((key, value) => !tmpKeys.contains(key)); + + for (var productVariation in productVariations) { + bool hasMatch = false; + for (var attr in productVariation.attributes) { + if (tmpSelectedObj[attr.name] == attr.option) { + hasMatch = true; + } else { + hasMatch = false; + break; + } + } + + if (hasMatch) { + return productVariation; + } + } + + return null; } } diff --git a/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart b/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart deleted file mode 100644 index 283779e..0000000 --- a/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class ProductImageViewerController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/product_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_loader_controller.dart deleted file mode 100644 index d619b55..0000000 --- a/LabelStoreMax/lib/app/controllers/product_loader_controller.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/app/controllers/woosignal_api_loader_controller.dart'; -import 'package:woosignal/models/response/product.dart'; - -class ProductLoaderController extends WooSignalApiLoaderController { - ProductLoaderController(); - - Future loadProducts( - {required bool Function(bool hasProducts) hasResults, - required void Function() didFinish, - List? productIds = const []}) async { - await load( - hasResults: hasResults, - didFinish: didFinish, - apiQuery: (api) => api.getProducts( - perPage: 50, - page: page, - include: productIds, - status: "publish", - stockStatus: "instock", - )); - } -} diff --git a/LabelStoreMax/lib/app/controllers/product_reviews_controller.dart b/LabelStoreMax/lib/app/controllers/product_reviews_controller.dart deleted file mode 100644 index 2430322..0000000 --- a/LabelStoreMax/lib/app/controllers/product_reviews_controller.dart +++ /dev/null @@ -1,14 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 'controller.dart'; - -class ProductReviewsController extends Controller { -} diff --git a/LabelStoreMax/lib/app/controllers/product_reviews_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_reviews_loader_controller.dart deleted file mode 100644 index 811c428..0000000 --- a/LabelStoreMax/lib/app/controllers/product_reviews_loader_controller.dart +++ /dev/null @@ -1,34 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/app/controllers/woosignal_api_loader_controller.dart'; -import 'package:woosignal/models/response/product_review.dart'; -import 'package:woosignal/models/response/product.dart'; - -class ProductReviewsLoaderController - extends WooSignalApiLoaderController { - ProductReviewsLoaderController(); - - Future loadProductReviews({ - 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", - )); - } -} diff --git a/LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart deleted file mode 100644 index 04b5bf0..0000000 --- a/LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart +++ /dev/null @@ -1,33 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/app/controllers/woosignal_api_loader_controller.dart'; -import 'package:woosignal/models/response/product.dart'; - -class ProductSearchLoaderController - extends WooSignalApiLoaderController { - ProductSearchLoaderController(); - - Future loadProducts( - {required bool Function(bool hasProducts) hasResults, - required void Function() didFinish, - required String? search}) async { - await load( - hasResults: hasResults, - didFinish: didFinish, - apiQuery: (api) => api.getProducts( - perPage: 100, - search: search, - page: page, - status: "publish", - stockStatus: "instock", - )); - } -} diff --git a/LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart b/LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart deleted file mode 100644 index 18d1068..0000000 --- a/LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart +++ /dev/null @@ -1,50 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/bootstrap/helpers.dart'; -import 'package:woosignal/woosignal.dart'; - -class WooSignalApiLoaderController { - List _results = []; - int page = 1; - bool _waitForNextRequest = false; - - WooSignalApiLoaderController(); - - Future load( - {required bool Function(bool hasProducts) hasResults, - required void Function() didFinish, - required Future> Function(WooSignal query) apiQuery}) async { - if (_waitForNextRequest) { - return; - } - _waitForNextRequest = true; - - List apiResults = await (appWooSignal((api) => apiQuery(api))); - - if (!hasResults(apiResults.isNotEmpty)) { - return; - } - - _results.addAll(apiResults); - - page = page + 1; - _waitForNextRequest = false; - didFinish(); - } - - List getResults() => _results; - - void clear() { - _results = []; - _waitForNextRequest = false; - page = 1; - } -} diff --git a/LabelStoreMax/lib/app/events/firebase_on_message_order_event.dart b/LabelStoreMax/lib/app/events/firebase_on_message_order_event.dart new file mode 100644 index 0000000..897f746 --- /dev/null +++ b/LabelStoreMax/lib/app/events/firebase_on_message_order_event.dart @@ -0,0 +1,37 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; +import '/bootstrap/helpers.dart'; +import '/resources/pages/notifications_page.dart'; +import '/resources/widgets/notification_icon_widget.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class FirebaseOnMessageOrderEvent implements NyEvent { + @override + final listeners = { + DefaultListener: DefaultListener(), + }; +} + +class DefaultListener extends NyListener { + @override + handle(dynamic event) async { + RemoteMessage message = event['RemoteMessage']; + + await _updateNotificationIconState(message); + } + + /// Update the notification icon state + _updateNotificationIconState(RemoteMessage message) async { + String title = getEnv('APP_NAME'); + if (message.notification?.title != null) { + title = message.notification!.title!; + } + String body = ""; + if (message.notification?.body != null) { + body = message.notification!.body!; + } + + await NyNotification.addNotification(title, body, meta: message.data); + updateState(NotificationIcon.state); + StateAction.refreshPage(NotificationsPage.path); + } +} diff --git a/LabelStoreMax/lib/app/events/login_event.dart b/LabelStoreMax/lib/app/events/login_event.dart index 132e954..2145640 100644 --- a/LabelStoreMax/lib/app/events/login_event.dart +++ b/LabelStoreMax/lib/app/events/login_event.dart @@ -1,4 +1,6 @@ import 'package:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/woosignal.dart'; +import 'package:wp_json_api/wp_json_api.dart'; class LoginEvent implements NyEvent { @override @@ -10,6 +12,9 @@ class LoginEvent implements NyEvent { class DefaultListener extends NyListener { @override handle(dynamic event) async { - // handle the payload from event + String? userId = await WPJsonAPI.wpUserId(); + if (userId != null) { + WooSignal.instance.setWpUserId(userId); + } } } diff --git a/LabelStoreMax/lib/app/events/logout_event.dart b/LabelStoreMax/lib/app/events/logout_event.dart index 6f11af7..c8305b0 100644 --- a/LabelStoreMax/lib/app/events/logout_event.dart +++ b/LabelStoreMax/lib/app/events/logout_event.dart @@ -1,4 +1,6 @@ +import '/app/models/cart.dart'; import 'package:nylo_framework/nylo_framework.dart'; +import 'package:wp_json_api/wp_json_api.dart'; class LogoutEvent implements NyEvent { @override @@ -8,6 +10,8 @@ class LogoutEvent implements NyEvent { class DefaultListener extends NyListener { @override handle(dynamic event) async { - // handle the payload from event + await WPJsonAPI.wpLogout(); + await Cart.getInstance.clear(); + routeToInitial(); } } diff --git a/LabelStoreMax/lib/app/events/order_notification_event.dart b/LabelStoreMax/lib/app/events/order_notification_event.dart new file mode 100644 index 0000000..6cb557f --- /dev/null +++ b/LabelStoreMax/lib/app/events/order_notification_event.dart @@ -0,0 +1,39 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:wp_json_api/wp_json_api.dart'; +import '/resources/pages/account_order_detail_page.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class OrderNotificationEvent implements NyEvent { + @override + final listeners = { + DefaultListener: DefaultListener(), + }; +} + +class DefaultListener extends NyListener { + @override + handle(dynamic event) async { + RemoteMessage message = event['RemoteMessage']; + + if (!message.data.containsKey('order_id')) { + return; + } + if (!message.data.containsKey('user_id')) { + return; + } + + String userId = message.data['user_id']; + + if ((await WPJsonAPI.wpUserLoggedIn()) != true) { + return; + } + + String? currentUserId = await WPJsonAPI.wpUserId(); + if (currentUserId != userId) { + return; + } + + routeTo(AccountOrderDetailPage.path, + data: int.parse(message.data['order_id'])); + } +} diff --git a/LabelStoreMax/lib/app/events/product_notification_event.dart b/LabelStoreMax/lib/app/events/product_notification_event.dart new file mode 100644 index 0000000..7f50ee4 --- /dev/null +++ b/LabelStoreMax/lib/app/events/product_notification_event.dart @@ -0,0 +1,24 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; +import '/resources/pages/product_detail_page.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class ProductNotificationEvent implements NyEvent { + @override + final listeners = { + DefaultListener: DefaultListener(), + }; +} + +class DefaultListener extends NyListener { + @override + handle(dynamic event) async { + RemoteMessage message = event['RemoteMessage']; + + if (!message.data.containsKey('product_id')) { + return; + } + + routeTo(ProductDetailPage.path, + data: int.parse(message.data['product_id'])); + } +} diff --git a/LabelStoreMax/lib/app/models/cart.dart b/LabelStoreMax/lib/app/models/cart.dart index 40af62b..b15fcb0 100644 --- a/LabelStoreMax/lib/app/models/cart.dart +++ b/LabelStoreMax/lib/app/models/cart.dart @@ -129,7 +129,7 @@ class Cart { await saveCartToPref(cartLineItems: cartLineItems); } - clear() async => NyStorage.delete(SharedKey.cart); + clear() async => await NyStorage.delete(SharedKey.cart); saveCartToPref({required List cartLineItems}) async { String json = jsonEncode(cartLineItems.map((i) => i.toJson()).toList()); diff --git a/LabelStoreMax/lib/app/models/cart_line_item.dart b/LabelStoreMax/lib/app/models/cart_line_item.dart index e0e3ad7..49cc38c 100644 --- a/LabelStoreMax/lib/app/models/cart_line_item.dart +++ b/LabelStoreMax/lib/app/models/cart_line_item.dart @@ -38,25 +38,25 @@ class CartLineItem { CartLineItem( {this.name, - this.productId, - this.variationId, - this.isManagedStock, - this.stockQuantity, - this.quantity = 1, - this.stockStatus, - this.shippingClassId, - this.taxStatus, - this.taxClass, - this.categories, - this.shippingIsTaxable, - this.variationOptions, - this.imageSrc, - this.subtotal, - this.onSale, - this.salePrice, - this.regularPrice, - this.total, - this.metaData = const []}); + this.productId, + this.variationId, + this.isManagedStock, + this.stockQuantity, + this.quantity = 1, + this.stockStatus, + this.shippingClassId, + this.taxStatus, + this.taxClass, + this.categories, + this.shippingIsTaxable, + this.variationOptions, + this.imageSrc, + this.subtotal, + this.onSale, + this.salePrice, + this.regularPrice, + this.total, + this.metaData = const []}); String getCartTotal() { return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2); @@ -64,7 +64,8 @@ class CartLineItem { String getPrice({bool formatToCurrency = false}) { if (formatToCurrency) { - return formatStringCurrency(total: (parseWcPrice(subtotal)).toStringAsFixed(2)); + return formatStringCurrency( + total: (parseWcPrice(subtotal)).toStringAsFixed(2)); } return (parseWcPrice(subtotal)).toStringAsFixed(2); } @@ -85,7 +86,8 @@ class CartLineItem { onSale = product.onSale; regularPrice = product.regularPrice; shippingIsTaxable = product.shippingTaxable; - List> data = product.metaData.map((e) => {e.key: e.value}).toList(); + List> data = + product.metaData.map((e) => {e.key: e.value}).toList(); metaData.addAll(data); imageSrc = product.images.isEmpty ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") @@ -96,9 +98,9 @@ class CartLineItem { CartLineItem.fromProductVariation( {int? quantityAmount, - required List options, - required ws_product.Product product, - required ProductVariation productVariation}) { + required List options, + required ws_product.Product product, + required ProductVariation productVariation}) { String? imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE"); if (product.images.isNotEmpty) { imageSrc = product.images.first.src; @@ -120,13 +122,15 @@ class CartLineItem { onSale = productVariation.onSale; this.imageSrc = imageSrc; salePrice = productVariation.salePrice; - List> data = product.metaData.map((e) => {e.key: e.value}).toList(); + List> data = + product.metaData.map((e) => {e.key: e.value}).toList(); metaData.addAll(data); regularPrice = productVariation.regularPrice; shippingIsTaxable = product.shippingTaxable; variationOptions = options.join("; "); total = productVariation.price; - appMetaData = product.metaData.map((e) => {"key": e.key, "value": e.value}).toList(); + appMetaData = + product.metaData.map((e) => {"key": e.key, "value": e.value}).toList(); } CartLineItem.fromJson(Map json) { @@ -137,8 +141,10 @@ class CartLineItem { shippingClassId = json['shipping_class_id'].toString(); taxStatus = json['tax_status']; stockQuantity = json['stock_quantity']; - isManagedStock = (json['is_managed_stock'] != null && - json['is_managed_stock'] is bool) ? json['is_managed_stock'] : false; + isManagedStock = + (json['is_managed_stock'] != null && json['is_managed_stock'] is bool) + ? json['is_managed_stock'] + : false; shippingIsTaxable = json['shipping_is_taxable']; subtotal = json['subtotal']; total = json['total']; @@ -147,7 +153,11 @@ class CartLineItem { imageSrc = json['image_src']; salePrice = json['sale_price']; regularPrice = json['regular_price']; - categories = json['categories'] == null ? null : List.of(json['categories'] as List).map((e) => ws_product.Category.fromJson(e)).toList(); + categories = json['categories'] == null + ? null + : List.of(json['categories'] as List) + .map((e) => ws_product.Category.fromJson(e)) + .toList(); onSale = json['on_sale']; variationOptions = json['variation_options']; metaData = []; @@ -156,11 +166,11 @@ class CartLineItem { } appMetaData = []; if (json['app_meta_data'] != null) { - appMetaData = List.from(json['app_meta_data']).cast>(); + appMetaData = + List.from(json['app_meta_data']).cast>(); } } - Map toJson() => { 'name': name, 'product_id': productId, @@ -182,6 +192,6 @@ class CartLineItem { 'on_sale': onSale, 'total': total, 'meta_data': metaData, - 'app_meta_data': appMetaData, + 'app_meta_data': appMetaData, }; } diff --git a/LabelStoreMax/lib/app/models/default_shipping.dart b/LabelStoreMax/lib/app/models/default_shipping.dart index 58f2908..0233601 100644 --- a/LabelStoreMax/lib/app/models/default_shipping.dart +++ b/LabelStoreMax/lib/app/models/default_shipping.dart @@ -7,6 +7,7 @@ // 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. + class DefaultShipping { String code; String? country; diff --git a/LabelStoreMax/lib/app/models/shipping_type.dart b/LabelStoreMax/lib/app/models/shipping_type.dart index 183b4fd..b10094a 100644 --- a/LabelStoreMax/lib/app/models/shipping_type.dart +++ b/LabelStoreMax/lib/app/models/shipping_type.dart @@ -7,6 +7,7 @@ // 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 '/bootstrap/helpers.dart'; import 'package:woosignal/models/response/shipping_method.dart'; diff --git a/LabelStoreMax/lib/app/models/user.dart b/LabelStoreMax/lib/app/models/user.dart deleted file mode 100644 index ddcb41e..0000000 --- a/LabelStoreMax/lib/app/models/user.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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_framework/nylo_framework.dart'; - -class User extends Model { - String? userId; - String? token; - - User(); - User.fromUserAuthResponse({this.userId, this.token}); - - @override - toJson() => {"token": token, "user_id": userId}; - - User.fromJson(dynamic data) { - token = data['token']; - userId = data['user_id']; - } -} diff --git a/LabelStoreMax/lib/app/networking/api_service.dart b/LabelStoreMax/lib/app/networking/api_service.dart index 136f0b9..5c97b67 100644 --- a/LabelStoreMax/lib/app/networking/api_service.dart +++ b/LabelStoreMax/lib/app/networking/api_service.dart @@ -2,14 +2,11 @@ import 'package:flutter/material.dart'; import '/app/networking/dio/interceptors/logging_interceptor.dart'; import 'package:nylo_framework/nylo_framework.dart'; -/* +/* ApiService |-------------------------------------------------------------------------- -| ApiService -| ------------------------------------------------------------------------- | Define your API endpoints | Learn more https://nylo.dev/docs/5.20.0/networking -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ class ApiService extends NyApiService { ApiService({BuildContext? buildContext}) : super(buildContext); diff --git a/LabelStoreMax/lib/app/providers/app_provider.dart b/LabelStoreMax/lib/app/providers/app_provider.dart index a09271e..f3a0f35 100644 --- a/LabelStoreMax/lib/app/providers/app_provider.dart +++ b/LabelStoreMax/lib/app/providers/app_provider.dart @@ -18,10 +18,11 @@ class AppProvider implements NyProvider { DeviceOrientation.portraitUp, ]); - await WooSignal.instance - .init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG'), + await WooSignal.instance.init( + appKey: getEnv('APP_KEY'), + debugMode: getEnv('APP_DEBUG'), encryptKey: getEnv('ENCRYPT_KEY', defaultValue: null), - encryptSecret: getEnv('ENCRYPT_SECRET', defaultValue: null) + encryptSecret: getEnv('ENCRYPT_SECRET', defaultValue: null), ); AppHelper.instance.appConfig = WooSignalApp(); @@ -46,7 +47,8 @@ class AppProvider implements NyProvider { }; // WooSignal Setup - WooSignalApp? wooSignalApp = await (appWooSignal((api) => api.getApp(encrypted: shouldEncrypt()))); + WooSignalApp? wooSignalApp = + await (appWooSignal((api) => api.getApp(encrypted: shouldEncrypt()))); Locale locale = Locale('en'); if (wooSignalApp != null) { @@ -55,15 +57,17 @@ class AppProvider implements NyProvider { if (wooSignalApp.wpLoginEnabled == 1) { if (wooSignalApp.wpLoginBaseUrl == null) { AppHelper.instance.appConfig?.wpLoginEnabled = 0; - NyLogger.debug('Set your stores domain on WooSignal. Go to Features > WP Login and add your domain to "Store Base Url"'); + NyLogger.debug( + '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; - NyLogger.debug('Set your stores Wp JSON path on WooSignal. Go to Features > WP Login and add your Wp JSON path to "WP API Path"'); + NyLogger.debug( + '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( + WPJsonAPI.instance.init( baseUrl: wooSignalApp.wpLoginBaseUrl ?? "", shouldDebug: getEnv('APP_DEBUG'), wpJsonPath: wooSignalApp.wpLoginWpApiPath ?? "", @@ -80,11 +84,10 @@ class AppProvider implements NyProvider { /// NyLocalization await NyLocalization.instance.init( - localeType: localeType, - languageCode: locale.languageCode, - languagesList: languagesList, - assetsDirectory: assetsDirectory, - valuesAsMap: valuesAsMap); + localeType: localeType, + languageCode: locale.languageCode, + assetsDirectory: assetsDirectory, + ); nylo.addLoader(loader); nylo.addLogo(logo); @@ -95,11 +98,11 @@ class AppProvider implements NyProvider { nylo.addControllers(controllers); nylo.addApiDecoders(apiDecoders); + await WPJsonAPI.wpAuth(); + return nylo; } @override - afterBoot(Nylo nylo) async { - - } -} \ No newline at end of file + afterBoot(Nylo nylo) async {} +} diff --git a/LabelStoreMax/lib/app/providers/event_provider.dart b/LabelStoreMax/lib/app/providers/event_provider.dart index 9ba9dd2..8b31a66 100644 --- a/LabelStoreMax/lib/app/providers/event_provider.dart +++ b/LabelStoreMax/lib/app/providers/event_provider.dart @@ -11,7 +11,5 @@ class EventProvider implements NyProvider { } @override - afterBoot(Nylo nylo) async { - - } + afterBoot(Nylo nylo) async {} } diff --git a/LabelStoreMax/lib/app/providers/firebase_provider.dart b/LabelStoreMax/lib/app/providers/firebase_provider.dart index fd5910e..9e2169a 100644 --- a/LabelStoreMax/lib/app/providers/firebase_provider.dart +++ b/LabelStoreMax/lib/app/providers/firebase_provider.dart @@ -1,21 +1,22 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:wp_json_api/models/wp_user.dart'; +import 'package:wp_json_api/wp_json_api.dart'; import '/bootstrap/app_helper.dart'; import '/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; + bool? firebaseFcmIsEnabled = + AppHelper.instance.appConfig?.firebaseFcmIsEnabled; firebaseFcmIsEnabled ??= getEnv('FCM_ENABLED', defaultValue: false); if (firebaseFcmIsEnabled != true) return; @@ -39,6 +40,11 @@ class FirebaseProvider implements NyProvider { return; } + WpUser? wpUser = await WPJsonAPI.wpUser(); + if (wpUser != null && wpUser.id != null) { + WooSignal.instance.setWpUserId(wpUser.id.toString()); + } + String? token = await messaging.getToken(); if (token != null) { WooSignal.instance.setFcmToken(token); diff --git a/LabelStoreMax/lib/app/providers/payments/cash_on_delivery.dart b/LabelStoreMax/lib/app/providers/payments/cash_on_delivery.dart index 200163b..34ab121 100644 --- a/LabelStoreMax/lib/app/providers/payments/cash_on_delivery.dart +++ b/LabelStoreMax/lib/app/providers/payments/cash_on_delivery.dart @@ -1,5 +1,3 @@ -// -// LabelCore // Label StoreMax // // Created by Anthony Gordon. @@ -9,9 +7,8 @@ // 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 '/resources/pages/checkout_status_page.dart'; import '/bootstrap/data/order_wc.dart'; import '/bootstrap/helpers.dart'; import '/resources/pages/checkout_confirmation_page.dart'; @@ -20,29 +17,28 @@ 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 { +cashOnDeliveryPay(context, {TaxRate? taxRate}) async { try { OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: false); Order? order = await (appWooSignal((api) => api.createOrder(orderWC))); - if (order != null) { - Navigator.pushNamed(context, "/checkout-status", arguments: order); - } else { + if (order == null) { showToastNotification( context, title: trans("Error"), description: trans("Something went wrong, please contact our store"), ); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); + return; } + routeTo(CheckoutStatusPage.path, data: order); } catch (_) { showToastNotification( context, title: trans("Error"), description: trans("Something went wrong, please contact our store"), ); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); } } diff --git a/LabelStoreMax/lib/app/providers/payments/example_pay.dart b/LabelStoreMax/lib/app/providers/payments/example_pay.dart index 2d55d0e..e54d0ef 100644 --- a/LabelStoreMax/lib/app/providers/payments/example_pay.dart +++ b/LabelStoreMax/lib/app/providers/payments/example_pay.dart @@ -1,5 +1,3 @@ -// -// LabelCore // Label StoreMax // // Created by Anthony Gordon. @@ -9,9 +7,8 @@ // 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 '/resources/pages/checkout_status_page.dart'; import '/bootstrap/data/order_wc.dart'; import '/bootstrap/helpers.dart'; import '/resources/pages/checkout_confirmation_page.dart'; @@ -56,13 +53,13 @@ examplePay(context, // CHECK IF ORDER IS NULL if (order != null) { - Navigator.pushNamed(context, "/checkout-status", arguments: order); - } else { showToastNotification( context, title: trans("Error"), description: trans("Something went wrong, please contact our store"), ); state.reloadState(showLoader: false); + return; } + routeTo(CheckoutStatusPage.path, data: order); } diff --git a/LabelStoreMax/lib/app/providers/payments/paypal_pay.dart b/LabelStoreMax/lib/app/providers/payments/paypal_pay.dart index 11b1f94..6714fd0 100644 --- a/LabelStoreMax/lib/app/providers/payments/paypal_pay.dart +++ b/LabelStoreMax/lib/app/providers/payments/paypal_pay.dart @@ -1,4 +1,4 @@ -// WooGym +// Label StoreMax // // Created by Anthony Gordon. // 2024, WooSignal Ltd. All rights reserved. @@ -23,8 +23,7 @@ import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; import 'package:nylo_framework/nylo_framework.dart'; -payPalPay(context, {required CheckoutConfirmationPageState state, TaxRate? taxRate}) async { - +payPalPay(context, {TaxRate? taxRate}) async { await checkout(taxRate, (total, billingDetails, cart) async { WooSignalApp? wooSignalApp = AppHelper.instance.appConfig; @@ -32,83 +31,98 @@ payPalPay(context, {required CheckoutConfirmationPageState state, TaxRate? taxRa String cartTotal = await cart.getTotal(); String? currencyCode = wooSignalApp?.currencyMeta?.code; - String shippingTotal = CheckoutSession.getInstance.shippingType?.getTotal() ?? "0"; + String shippingTotal = + CheckoutSession.getInstance.shippingType?.getTotal() ?? "0"; - String description = "(${cartLineItems.length}) items from ${getEnv('APP_NAME')}".tr(arguments: {"appName": getEnv('APP_NAME')}); + String description = + "(${cartLineItems.length}) items from ${getEnv('APP_NAME')}" + .tr(arguments: {"appName": getEnv('APP_NAME')}); - Navigator.of(context).push(MaterialPageRoute( - builder: (BuildContext context) => PaypalCheckoutView( - sandboxMode: getEnv('PAYPAL_LIVE_MODE') != true, - clientId: getEnv('PAYPAL_CLIENT_ID'), - secretKey: getEnv('PAYPAL_SECRET_KEY'), - note: "Contact us for any questions on your order.".tr(), - transactions: [ - { - "amount": { - "total": total, - "currency": currencyCode?.toUpperCase(), - "details": { - "subtotal": cartTotal, - "shipping": shippingTotal, - "shipping_discount": 0 + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => PaypalCheckoutView( + sandboxMode: getEnv('PAYPAL_LIVE_MODE') != true, + clientId: getEnv('PAYPAL_CLIENT_ID'), + secretKey: getEnv('PAYPAL_SECRET_KEY'), + note: "Contact us for any questions on your order.".tr(), + transactions: [ + { + "amount": { + "total": total, + "currency": currencyCode?.toUpperCase(), + "details": { + "subtotal": cartTotal, + "shipping": shippingTotal, + "shipping_discount": 0 + } + }, + "description": description, + "item_list": { + "items": cartLineItems + .map((item) => { + "name": item.name, + "quantity": item.quantity, + "price": item.total, + "currency": currencyCode?.toUpperCase() + }) + .toList(), + "shipping_address": { + "recipient_name": + "${billingDetails?.shippingAddress?.nameFull()}", + "line1": billingDetails?.shippingAddress?.addressLine, + "line2": "", + "city": billingDetails?.shippingAddress?.city, + "country_code": billingDetails + ?.shippingAddress?.customerCountry?.countryCode, + "postal_code": billingDetails?.shippingAddress?.postalCode, + "phone": billingDetails?.shippingAddress?.phoneNumber, + "state": billingDetails + ?.shippingAddress?.customerCountry?.state?.name + }, } - }, - "description": description, - "item_list": { - "items": cartLineItems.map((item) => { - "name": item.name, - "quantity": item.quantity, - "price": item.total, - "currency": currencyCode?.toUpperCase() - }).toList(), + } + ], + onSuccess: (Map params) async { + OrderWC orderWC = await buildOrderWC(taxRate: taxRate); + Order? order = + await (appWooSignal((api) => api.createOrder(orderWC))); - "shipping_address": { - "recipient_name": "${billingDetails?.shippingAddress?.nameFull()}", - "line1": billingDetails?.shippingAddress?.addressLine, - "line2": "", - "city": billingDetails?.shippingAddress?.city, - "country_code": billingDetails?.shippingAddress?.customerCountry?.countryCode, - "postal_code": billingDetails?.shippingAddress?.postalCode, - "phone": billingDetails?.shippingAddress?.phoneNumber, - "state": billingDetails?.shippingAddress?.customerCountry?.state?.name - }, + if (order == null) { + showToastNotification( + context, + title: trans("Error"), + description: + trans("Something went wrong, please contact our store"), + ); + updateState(CheckoutConfirmationPage.path, + data: {"reloadState": false}); + return; } - } - ], - onSuccess: (Map params) async { - OrderWC orderWC = await buildOrderWC(taxRate: taxRate); - Order? order = await (appWooSignal((api) => api.createOrder(orderWC))); - if (order == null) { + routeTo(CheckoutStatusPage.path, data: order); + }, + onError: (error) { + NyLogger.error(error.toString()); showToastNotification( context, title: trans("Error"), - description: trans("Something went wrong, please contact our store"), + description: + trans("Something went wrong, please contact our store"), ); - state.reloadState(showLoader: false); - return; - } - - routeTo(CheckoutStatusPage.path, data: order); - }, - onError: (error) { - NyLogger.error(error.toString()); - showToastNotification( - context, - title: trans("Error"), - description: - trans("Something went wrong, please contact our store"), - ); - updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); - }, - onCancel: () { - showToastNotification( - context, - title: trans("Payment Cancelled"), - description: trans("The payment has been cancelled"), - ); - updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); - }, - ),),); + updateState(CheckoutConfirmationPage.path, + data: {"reloadState": false}); + }, + onCancel: () { + showToastNotification( + context, + title: trans("Payment Cancelled"), + description: trans("The payment has been cancelled"), + ); + updateState(CheckoutConfirmationPage.path, + data: {"reloadState": false}); + }, + ), + ), + ); }); } diff --git a/LabelStoreMax/lib/app/providers/payments/razorpay_pay.dart b/LabelStoreMax/lib/app/providers/payments/razorpay_pay.dart index 06da0ef..e3d2679 100644 --- a/LabelStoreMax/lib/app/providers/payments/razorpay_pay.dart +++ b/LabelStoreMax/lib/app/providers/payments/razorpay_pay.dart @@ -1,6 +1,4 @@ -// -// LabelCore -// Label StoreMAX +// Label StoreMax // // Created by Anthony Gordon. // 2024, WooSignal Ltd. All rights reserved. @@ -9,9 +7,8 @@ // 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 '/resources/pages/checkout_status_page.dart'; import '/app/models/cart.dart'; import '/bootstrap/data/order_wc.dart'; import '/bootstrap/helpers.dart'; @@ -22,35 +19,34 @@ 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(context, {TaxRate? taxRate}) async { Razorpay razorpay = Razorpay(); razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, - (PaymentSuccessResponse response) async { - OrderWC orderWC = await buildOrderWC(taxRate: taxRate); + (PaymentSuccessResponse response) async { + 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( - 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); - }); + if (order != null) { + showToastNotification( + context, + title: "Error".tr(), + description: trans("Something went wrong, please contact our store"), + ); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); + return; + } + Cart.getInstance.clear(); + routeTo(CheckoutStatusPage.path, data: order); + }); razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) { showToastNotification(context, title: trans("Error"), description: response.message ?? "", style: ToastNotificationStyleType.WARNING); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); }); razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet); @@ -72,10 +68,10 @@ razorPay(context, } }; - state.reloadState(showLoader: true); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": true}); razorpay.open(options); }); } -void _handleExternalWallet(ExternalWalletResponse response) {} \ No newline at end of file +void _handleExternalWallet(ExternalWalletResponse response) {} diff --git a/LabelStoreMax/lib/app/providers/payments/stripe_pay.dart b/LabelStoreMax/lib/app/providers/payments/stripe_pay.dart index fc4ffbb..3dad6e6 100644 --- a/LabelStoreMax/lib/app/providers/payments/stripe_pay.dart +++ b/LabelStoreMax/lib/app/providers/payments/stripe_pay.dart @@ -1,5 +1,3 @@ -// -// LabelCore // Label StoreMax // // Created by Anthony Gordon. @@ -9,9 +7,9 @@ // 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 '/resources/pages/checkout_status_page.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/data/order_wc.dart'; import '/bootstrap/helpers.dart'; @@ -23,8 +21,7 @@ import 'package:woosignal/models/response/order.dart'; import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; -stripePay(context, - {required CheckoutConfirmationPageState state, TaxRate? taxRate}) async { +stripePay(context, {TaxRate? taxRate}) async { WooSignalApp? wooSignalApp = AppHelper.instance.appConfig; bool liveMode = getEnv('STRIPE_LIVE_MODE') == null @@ -67,13 +64,13 @@ stripePay(context, description: trans("Something went wrong, please try again."), icon: Icons.payment, style: ToastNotificationStyleType.WARNING); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); return; } await Stripe.instance.initPaymentSheet( paymentSheetParameters: SetupPaymentSheetParameters( - style: Theme.of(state.context).brightness == Brightness.light + style: Theme.of(context).brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark, merchantDisplayName: @@ -103,7 +100,7 @@ stripePay(context, return; } - state.reloadState(showLoader: true); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": true}); OrderWC orderWC = await buildOrderWC(taxRate: taxRate); Order? order = await (appWooSignal((api) => api.createOrder(orderWC))); @@ -114,11 +111,12 @@ stripePay(context, title: trans("Error"), description: trans("Something went wrong, please contact our store"), ); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); return; } - routeTo('/checkout-status', navigationType: NavigationType.pushAndForgetAll, data: order); + routeTo(CheckoutStatusPage.path, + navigationType: NavigationType.pushAndForgetAll, data: order); } on StripeException catch (e) { if (getEnv('APP_DEBUG', defaultValue: true)) { NyLogger.error(e.error.message!); @@ -130,7 +128,7 @@ stripePay(context, icon: Icons.payment, style: ToastNotificationStyleType.WARNING, ); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); } catch (ex) { if (getEnv('APP_DEBUG', defaultValue: true)) { NyLogger.error(ex.toString()); @@ -142,6 +140,6 @@ stripePay(context, icon: Icons.payment, style: ToastNotificationStyleType.WARNING, ); - state.reloadState(showLoader: false); + updateState(CheckoutConfirmationPage.path, data: {"reloadState": false}); } } diff --git a/LabelStoreMax/lib/app/providers/route_provider.dart b/LabelStoreMax/lib/app/providers/route_provider.dart index 6bef6ee..e3fc30f 100644 --- a/LabelStoreMax/lib/app/providers/route_provider.dart +++ b/LabelStoreMax/lib/app/providers/route_provider.dart @@ -12,9 +12,10 @@ class RouteProvider implements NyProvider { @override afterBoot(Nylo nylo) async { - String initialRoute = AppHelper.instance.appConfig!.appStatus != null - ? '/home' - : '/no-connection'; - nylo.setInitialRoute(initialRoute); + if (AppHelper.instance.appConfig?.appStatus == null) { + nylo.initRoutes(initialRoute: '/no-connection'); + return; + } + nylo.initRoutes(); } } diff --git a/LabelStoreMax/lib/bootstrap/boot.dart b/LabelStoreMax/lib/bootstrap/boot.dart index 086af55..a65fa5f 100644 --- a/LabelStoreMax/lib/bootstrap/boot.dart +++ b/LabelStoreMax/lib/bootstrap/boot.dart @@ -1,9 +1,11 @@ /// boot application library; + import '/config/providers.dart'; import 'package:nylo_framework/nylo_framework.dart'; class Boot { static Future nylo() async => await bootApplication(providers); - static Future finished(Nylo nylo) async => await bootFinished(nylo, providers); + static Future finished(Nylo nylo) async => + await bootFinished(nylo, providers); } diff --git a/LabelStoreMax/lib/bootstrap/data/order_wc.dart b/LabelStoreMax/lib/bootstrap/data/order_wc.dart index b442752..e7721c7 100644 --- a/LabelStoreMax/lib/bootstrap/data/order_wc.dart +++ b/LabelStoreMax/lib/bootstrap/data/order_wc.dart @@ -10,13 +10,15 @@ import 'dart:io'; +import 'package:wp_json_api/models/wp_user.dart'; +import 'package:wp_json_api/wp_json_api.dart'; + import '/app/models/billing_details.dart'; import '/app/models/cart.dart'; import '/app/models/cart_line_item.dart'; import '/app/models/checkout_session.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/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'; @@ -37,9 +39,10 @@ Future 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") - : 0; + WpUser? wpUser = await WPJsonAPI.wpUser(); + if (wpUser != null && wooSignalApp.wpLoginEnabled == 1) { + orderWC.customerId = int.parse(wpUser.id.toString()); + } List lineItems = []; List cartItems = await Cart.getInstance.getCart(); @@ -52,7 +55,9 @@ Future buildOrderWC({TaxRate? taxRate, bool markPaid = true}) async { tmpLineItem.variationId = cartItem.variationId; } - tmpLineItem.subtotal = (parseWcPrice(cartItem.subtotal) * parseWcPrice(cartItem.quantity.toString())).toString(); + tmpLineItem.subtotal = (parseWcPrice(cartItem.subtotal) * + parseWcPrice(cartItem.quantity.toString())) + .toString(); lineItems.add(tmpLineItem); } diff --git a/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart b/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart index 7332cf9..e735d3f 100644 --- a/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart +++ b/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart @@ -13,4 +13,6 @@ enum SortByType { highToLow, nameAZ, nameZA, + dateAsc, + dateDesc, } diff --git a/LabelStoreMax/lib/bootstrap/extensions.dart b/LabelStoreMax/lib/bootstrap/extensions.dart index a86c8ce..b254081 100644 --- a/LabelStoreMax/lib/bootstrap/extensions.dart +++ b/LabelStoreMax/lib/bootstrap/extensions.dart @@ -35,9 +35,9 @@ extension DateTimeExtension on DateTime? { } bool? isBetween( - DateTime fromDateTime, - DateTime toDateTime, - ) { + DateTime fromDateTime, + DateTime toDateTime, + ) { final date = this; if (date != null) { final isAfter = date.isAfterOrEqualTo(fromDateTime) ?? false; @@ -46,4 +46,4 @@ extension DateTimeExtension on DateTime? { } return null; } -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/bootstrap/helpers.dart b/LabelStoreMax/lib/bootstrap/helpers.dart index 491b078..011c87f 100644 --- a/LabelStoreMax/lib/bootstrap/helpers.dart +++ b/LabelStoreMax/lib/bootstrap/helpers.dart @@ -10,23 +10,21 @@ import 'dart:convert'; import 'package:collection/collection.dart' show IterableExtension; -import 'package:flutter/cupertino.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:wp_json_api/models/wp_user.dart'; +import 'package:wp_json_api/wp_json_api.dart'; import '/app/models/billing_details.dart'; import '/app/models/cart.dart'; import '/app/models/cart_line_item.dart'; import '/app/models/checkout_session.dart'; import '/app/models/default_shipping.dart'; import '/app/models/payment_type.dart'; -import '/app/models/user.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/enums/symbol_position_enums.dart'; import '/bootstrap/extensions.dart'; import '/bootstrap/shared_pref/shared_key.dart'; import '/config/currency.dart'; import '/config/payment_gateways.dart'; -import '/resources/widgets/no_results_for_products_widget.dart'; -import '/resources/widgets/woosignal_ui.dart'; -import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:intl/intl.dart'; import 'package:flutter/material.dart'; import 'package:html/parser.dart'; @@ -34,7 +32,6 @@ 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:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:status_alert/status_alert.dart'; import 'package:woosignal/models/response/product.dart'; import 'package:woosignal/models/response/tax_rate.dart'; @@ -43,8 +40,9 @@ 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 getUser() async => - (await (NyStorage.read(SharedKey.authUser))); +Future getUser() async { + return await WPJsonAPI.wpUser(); +} Future appWooSignal(Function(WooSignal api) api) async { return await api(WooSignal.instance); @@ -137,9 +135,8 @@ String moneyFormatter(double amount) { MoneyFormatter fmf = MoneyFormatter( amount: amount, settings: MoneyFormatterSettings( - symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative, - symbolAndNumberSeparator: "" - ), + symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative, + symbolAndNumberSeparator: ""), ); if (appCurrencySymbolPosition == SymbolPositionType.left) { return fmf.output.symbolOnLeft; @@ -232,7 +229,8 @@ Future workoutShippingCostWC({required String? sum}) async { String percentVal = newSum.replaceAllMapped( defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) { if (replacePercent.groupCount >= 1) { - String strPercentage = "( ($orderTotal * ${replacePercent.group(1)}) / 100 )"; + String strPercentage = + "( ($orderTotal * ${replacePercent.group(1)}) / 100 )"; double? calPercentage = strCal(sum: strPercentage); // MIN @@ -301,7 +299,8 @@ Future workoutShippingClassCostWC( String percentVal = newSum.replaceAllMapped( defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) { if (replacePercent.groupCount >= 1) { - String strPercentage = "( ($orderTotal * ${replacePercent.group(1)}) / 100 )"; + String strPercentage = + "( ($orderTotal * ${replacePercent.group(1)}) / 100 )"; double? calPercentage = strCal(sum: strPercentage); // MIN @@ -418,60 +417,6 @@ String formatForDateTime(FormatType formatType) { double parseWcPrice(String? price) => (double.tryParse(price ?? "0") ?? 0); -Widget refreshableScroll(context, - {required refreshController, - required VoidCallback onRefresh, - required VoidCallback onLoading, - required List products, - required onTap, - key}) { - return SmartRefresher( - enablePullDown: true, - enablePullUp: true, - footer: CustomFooter( - builder: (BuildContext context, LoadStatus? mode) { - Widget body; - if (mode == LoadStatus.idle) { - body = Text(trans("pull up load")); - } else if (mode == LoadStatus.loading) { - body = CupertinoActivityIndicator(); - } else if (mode == LoadStatus.failed) { - body = Text(trans("Load Failed! Click retry!")); - } else if (mode == LoadStatus.canLoading) { - body = Text(trans("release to load more")); - } else { - body = Text(trans("No more products")); - } - return Container( - height: 55.0, - child: Center(child: body), - ); - }, - ), - controller: refreshController, - onRefresh: onRefresh, - onLoading: onLoading, - child: products.isEmpty - ? NoResultsForProductsWidget() - : StaggeredGrid.count( - crossAxisCount: 2, - mainAxisSpacing: 4.0, - crossAxisSpacing: 4.0, - children: products.map((product) { - return StaggeredGridTile.fit( - crossAxisCellCount: 1, - child: Container( - height: 350, - child: ProductItemContainer( - product: product, - onTap: onTap, - ), - ), - ); - }).toList()), - ); -} - class UserAuth { UserAuth._privateConstructor(); static final UserAuth instance = UserAuth._privateConstructor(); @@ -627,7 +572,9 @@ 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; + return dateTime.isBetween( + DateTime.now().subtract(Duration(days: 2)), DateTime.now()) ?? + false; } on Exception catch (e) { NyLogger.error(e.toString()); } @@ -644,4 +591,218 @@ bool shouldEncrypt() { return false; } return true; -} \ No newline at end of file +} + +bool isFirebaseEnabled() { + bool? firebaseFcmIsEnabled = + AppHelper.instance.appConfig?.firebaseFcmIsEnabled; + firebaseFcmIsEnabled ??= getEnv('FCM_ENABLED', defaultValue: false); + + return firebaseFcmIsEnabled == true; +} + +class NotificationItem extends Model { + String? id; + String? title; + String? message; + bool? hasRead; + String? type; + Map? meta; + String? createdAt; + + NotificationItem( + {this.title, + this.message, + this.id, + this.type, + this.meta, + this.createdAt, + this.hasRead = false}); + + NotificationItem.fromJson(Map json) + : id = json['id'], + title = json['title'], + type = json['type'], + meta = json['meta'], + message = json['message'], + hasRead = json['has_read'], + createdAt = json['created_at']; + + fromJson(Map json) { + id = json['id']; + title = json['title']; + type = json['type']; + meta = json['meta']; + message = json['message']; + hasRead = json['has_read']; + createdAt = json['created_at']; + } + + @override + Map toJson() => { + 'id': id, + 'title': title, + 'type': type, + 'meta': meta, + 'message': message, + 'has_read': hasRead, + "created_at": createdAt + }; +} + +class NyNotification { + static final String _storageKey = "app_notifications"; + + static String storageKey() => _storageKey; + + /// Add a notification + static addNotification(String title, String message, + {String? id, Map? meta}) async { + NotificationItem notificationItem = NotificationItem.fromJson({ + "id": id, + "title": title, + "message": message, + "meta": meta, + "has_read": false, + "created_at": DateTime.now().toDateTimeString() + }); + await NyStorage.addToCollection(storageKey(), + item: notificationItem, + allowDuplicates: false, + modelDecoders: { + NotificationItem: (data) => NotificationItem.fromJson(data), + }); + } + + /// Get all notifications + static Future> allNotifications() async { + List notifications = + await NyStorage.readCollection("app_notifications", + modelDecoders: { + NotificationItem: (data) => NotificationItem.fromJson(data), + }); + String? userId = await WPJsonAPI.wpUserId(); + notifications.removeWhere((notification) { + if (notification.meta != null && + notification.meta!.containsKey('user_id')) { + if (notification.meta?['user_id'] != userId) { + return true; + } + } + return false; + }); + + await NyStorage.saveCollection(storageKey(), notifications); + + return notifications; + } + + /// Get all notifications not read + static Future> allNotificationsNotRead() async { + List notifications = await allNotifications(); + return notifications.where((element) => element.hasRead == false).toList(); + } + + /// Mark notification as read by index + static markReadByIndex(int index) async { + await NyStorage.updateCollectionByIndex(index, (item) { + item as NotificationItem; + item.hasRead = true; + return item; + }, key: storageKey()); + } + + /// Mark all notifications as read + static markReadAll() async { + List notifications = await allNotifications(); + for (var i = 0; i < notifications.length; i++) { + await markReadByIndex(i); + } + } + + /// Clear all notifications + static clearAllNotifications() async { + await NyStorage.deleteCollection(storageKey()); + } + + /// Render notifications + static Widget renderNotifications( + Widget Function(List notificationItems) child, + {Widget? loading}) { + return NyFutureBuilder( + future: allNotifications(), + child: (context, data) { + if (data == null) { + return SizedBox.shrink(); + } + return child(data); + }, + loading: loading); + } + + /// Render list of notifications + static Widget renderListNotifications( + Widget Function(NotificationItem notificationItems) child, + {Widget? loading}) { + return NyFutureBuilder( + future: allNotifications(), + child: (context, data) { + if (data == null) { + return SizedBox.shrink(); + } + return NyListView(child: (context, item) { + item as NotificationItem; + return child(item); + }, data: () async { + return data.reversed.toList(); + }); + }, + loading: loading); + } + + /// Render list of notifications + static Widget renderListNotificationsWithSeparator( + Widget Function(NotificationItem notificationItems) child, + {Widget? loading}) { + return NyFutureBuilder( + future: allNotifications(), + child: (context, data) { + if (data == null) { + return SizedBox.shrink(); + } + return NyListView.separated( + child: (context, item) { + item as NotificationItem; + return child(item); + }, + data: () async { + return data.reversed.toList(); + }, + separatorBuilder: (context, index) { + return Divider( + color: Colors.grey.shade100, + ); + }, + ); + }, + loading: loading); + } +} + +Future canSeeRemoteMessage(RemoteMessage message) async { + if (!message.data.containsKey('user_id')) { + return true; + } + + String userId = message.data['user_id']; + + if ((await WPJsonAPI.wpUserLoggedIn()) != true) { + return false; + } + + String? currentUserId = await WPJsonAPI.wpUserId(); + if (currentUserId != userId) { + return false; + } + return true; +} diff --git a/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart b/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart index 2f9b81a..70b5aa4 100644 --- a/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart +++ b/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart @@ -9,7 +9,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. class SharedKey { - static const String authUser = "DEFAULT_SP_USER"; static const String cart = "CART_SESSION"; static const String customerBillingDetails = "CS_BILLING_DETAILS"; static const String customerShippingDetails = "CS_SHIPPING_DETAILS"; diff --git a/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart b/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart deleted file mode 100644 index 17ddd0b..0000000 --- a/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Label StoreMax -// -// Created by Anthony Gordon. -// 2024, 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 '/app/models/cart.dart'; -import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/shared_key.dart'; -import 'package:nylo_framework/nylo_framework.dart'; - -Future authCheck() async => ((await getUser()) != null); - -Future readAuthToken() async => (await getUser())!.token; - -Future readUserId() async => (await getUser())!.userId; - -authLogout(BuildContext context) async { - await NyStorage.delete(SharedKey.authUser); - Cart.getInstance.clear(); - navigatorPush(context, routeName: "/home", forgetAll: true); -} diff --git a/LabelStoreMax/lib/config/currency.dart b/LabelStoreMax/lib/config/currency.dart index fa22a5c..6ad845e 100644 --- a/LabelStoreMax/lib/config/currency.dart +++ b/LabelStoreMax/lib/config/currency.dart @@ -1,11 +1,8 @@ -/* +/* CURRENCY |-------------------------------------------------------------------------- -| CURRENCY -| | Configure which currency you want to use. | Docs here: https://woosignal.com/docs/app/label-storemax -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ import '/bootstrap/enums/symbol_position_enums.dart'; diff --git a/LabelStoreMax/lib/config/decoders.dart b/LabelStoreMax/lib/config/decoders.dart index 7125cc0..f9e62c4 100644 --- a/LabelStoreMax/lib/config/decoders.dart +++ b/LabelStoreMax/lib/config/decoders.dart @@ -1,36 +1,24 @@ -import '/app/controllers/account_order_detail_controller.dart'; -import '/app/controllers/browse_category_controller.dart'; -import '/app/controllers/checkout_status_controller.dart'; -import '/app/controllers/leave_review_controller.dart'; +import '/bootstrap/helpers.dart'; + import '/app/controllers/product_detail_controller.dart'; -import '/app/controllers/product_image_viewer_controller.dart'; -import '/app/controllers/product_reviews_controller.dart'; -import '/app/models/user.dart'; import '/app/networking/api_service.dart'; -/* +/* Model Decoders |-------------------------------------------------------------------------- -| Model Decoders -| ------------------------------------------------------------------------- | Model decoders are used in 'app/networking/' for morphing json payloads | into Models. Learn more https://nylo.dev/docs/5.20.0/decoders#model-decoders -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final Map modelDecoders = { - // ... - User: (data) => User.fromJson(data) + NotificationItem: (data) => NotificationItem.fromJson(data), }; -/* -|-------------------------------------------------------------------------- -| API Decoders +/* API Decoders | ------------------------------------------------------------------------- | API decoders are used when you need to access an API service using the | 'api' helper. E.g. api((request) => request.fetchData()); | Learn more https://nylo.dev/docs/5.20.0/decoders#api-decoders -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final Map apiDecoders = { ApiService: () => ApiService(), @@ -38,25 +26,15 @@ final Map apiDecoders = { // ... }; -/* -|-------------------------------------------------------------------------- -| Controller Decoders +/* Controller Decoders | ------------------------------------------------------------------------- | Controller are used in pages. | E.g. NyPage | | Learn more https://nylo.dev/docs/5.20.0/controllers#using-controllers-with-ny-page -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final Map controllers = { ProductDetailController: () => ProductDetailController(), - AccountOrderDetailController: () => AccountOrderDetailController(), - BrowseCategoryController: () => BrowseCategoryController(), - CheckoutStatusController: () => CheckoutStatusController(), - LeaveReviewController: () => LeaveReviewController(), - ProductImageViewerController: () => ProductImageViewerController(), - ProductReviewsController: () => ProductReviewsController() // ... - -}; \ No newline at end of file +}; diff --git a/LabelStoreMax/lib/config/design.dart b/LabelStoreMax/lib/config/design.dart index 81419a5..70a1296 100644 --- a/LabelStoreMax/lib/config/design.dart +++ b/LabelStoreMax/lib/config/design.dart @@ -1,18 +1,16 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; import '/config/toast_notification.dart'; import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/toast_notification_widget.dart'; -import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; -/* +/* Design |-------------------------------------------------------------------------- -| Design | Contains widgets used in the Nylo framework. | | Learn more: https://nylo.dev/docs/5.20.0/themes -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ Widget logo = StoreLogo(); // resources/widgets/woosignal_ui.dart @@ -20,13 +18,16 @@ Widget logo = StoreLogo(); Widget loader = AppLoaderWidget(); // resources/widgets/app_loader_widget.dart -Widget getToastNotificationWidget({ - required ToastNotificationStyleType style, - Function(ToastNotificationStyleMetaHelper helper)? toastNotificationStyleMeta, Function? onDismiss}) { +Widget getToastNotificationWidget( + {required ToastNotificationStyleType style, + Function(ToastNotificationStyleMetaHelper helper)? + toastNotificationStyleMeta, + Function? onDismiss}) { if (toastNotificationStyleMeta == null) return SizedBox.shrink(); - ToastMeta toastMeta = toastNotificationStyleMeta(NyToastNotificationStyleMetaHelper(style)); + ToastMeta toastMeta = + toastNotificationStyleMeta(NyToastNotificationStyleMetaHelper(style)); return ToastNotification(toastMeta, onDismiss: onDismiss); // resources/widgets/toast_notification.dart -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/config/events.dart b/LabelStoreMax/lib/config/events.dart index 5a3ff14..1ab8ef8 100644 --- a/LabelStoreMax/lib/config/events.dart +++ b/LabelStoreMax/lib/config/events.dart @@ -1,19 +1,23 @@ +import '/app/events/firebase_on_message_order_event.dart'; +import '/app/events/order_notification_event.dart'; +import '/app/events/product_notification_event.dart'; import '/app/events/login_event.dart'; import '/app/events/logout_event.dart'; import 'package:nylo_framework/nylo_framework.dart'; -/* +/* Events |-------------------------------------------------------------------------- -| Events | Add your "app/events" here. | Events can be fired using: event(); | | Learn more: https://nylo.dev/docs/5.20.0/events -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final Map events = { LoginEvent: LoginEvent(), LogoutEvent: LogoutEvent(), AuthUserEvent: AuthUserEvent(), + FirebaseOnMessageOrderEvent: FirebaseOnMessageOrderEvent(), + OrderNotificationEvent: OrderNotificationEvent(), + ProductNotificationEvent: ProductNotificationEvent(), }; diff --git a/LabelStoreMax/lib/config/font.dart b/LabelStoreMax/lib/config/font.dart index 2ef2974..767285c 100644 --- a/LabelStoreMax/lib/config/font.dart +++ b/LabelStoreMax/lib/config/font.dart @@ -1,17 +1,14 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -/* +/* Font |-------------------------------------------------------------------------- -| Font -| | Uses Google Fonts - https://pub.dev/packages/google_fonts | | e.g. updating the font from "montserrat" to "lato" | before: final TextStyle appThemeFont = GoogleFonts.montserrat(); | after: final TextStyle appThemeFont = GoogleFonts.lato(); -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ TextStyle appFont = GoogleFonts.poppins(); diff --git a/LabelStoreMax/lib/config/localization.dart b/LabelStoreMax/lib/config/localization.dart index dc9cdd0..c82d772 100644 --- a/LabelStoreMax/lib/config/localization.dart +++ b/LabelStoreMax/lib/config/localization.dart @@ -1,32 +1,23 @@ import 'package:nylo_framework/nylo_framework.dart'; -/* +/* localeType |-------------------------------------------------------------------------- -| localeType -| ------------------------------------------------------------------------- | Define if you want the application to read the locale from the users | device settings or as you've defined in the [languageCode]. -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final LocaleType localeType = LocaleType.asDefined; // device, asDefined -/* +/* languageCode |-------------------------------------------------------------------------- -| languageCode -| ------------------------------------------------------------------------- | Define the language code you want to use. E.g. en, es, ar. | The language code should match the name of the file i.e /lang/es.json -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final String? languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en"); -/* +/* languagesList |-------------------------------------------------------------------------- -| languagesList -| ------------------------------------------------------------------------- | Add a list of supported languages. -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final List languagesList = const [ 'en', 'es', @@ -37,21 +28,15 @@ final List languagesList = const [ 'zh' ]; -/* +/* assetsDirectory |-------------------------------------------------------------------------- -| assetsDirectory -| ------------------------------------------------------------------------- | Asset directory for your languages. -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final String assetsDirectory = 'lang/'; -/* +/* valuesAsMap |-------------------------------------------------------------------------- -| valuesAsMap -| ------------------------------------------------------------------------- | If you want to define your own language map in code rather than using | the asset json files. -|-------------------------------------------------------------------------- -*/ +|--------------------------------------------------------------------------*/ final Map valuesAsMap = {}; diff --git a/LabelStoreMax/lib/config/payment_gateways.dart b/LabelStoreMax/lib/config/payment_gateways.dart index 1b57bdf..d75df8d 100644 --- a/LabelStoreMax/lib/config/payment_gateways.dart +++ b/LabelStoreMax/lib/config/payment_gateways.dart @@ -6,14 +6,11 @@ import '/app/providers/payments/stripe_pay.dart'; import '/bootstrap/helpers.dart'; import 'package:nylo_framework/nylo_framework.dart'; -/* +/* PAYMENT GATEWAYS |-------------------------------------------------------------------------- -| PAYMENT GATEWAYS -| | Configure which payment gateways you want to use. | Docs here: https://woosignal.com/docs/app/label-storemax -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ const appPaymentGateways = []; // Available: "Stripe", "CashOnDelivery", "PayPal", "RazorPay" diff --git a/LabelStoreMax/lib/config/providers.dart b/LabelStoreMax/lib/config/providers.dart index 9d7755c..2e41b9f 100644 --- a/LabelStoreMax/lib/config/providers.dart +++ b/LabelStoreMax/lib/config/providers.dart @@ -4,21 +4,17 @@ import '/app/providers/event_provider.dart'; import '/app/providers/route_provider.dart'; import 'package:nylo_framework/nylo_framework.dart'; -/* +/* Providers |-------------------------------------------------------------------------- -| Providers | Add your "app/providers" here. | Providers are booted when your application start. | | Learn more: https://nylo.dev/docs/5.20.0/providers -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final Map providers = { AppProvider: AppProvider(), RouteProvider: RouteProvider(), EventProvider: EventProvider(), FirebaseProvider: FirebaseProvider(), - }; - diff --git a/LabelStoreMax/lib/config/storage_keys.dart b/LabelStoreMax/lib/config/storage_keys.dart index b28224f..4869b9b 100644 --- a/LabelStoreMax/lib/config/storage_keys.dart +++ b/LabelStoreMax/lib/config/storage_keys.dart @@ -1,13 +1,11 @@ -/* +/* Storage Keys |-------------------------------------------------------------------------- -| 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.20.0/storage#storage-keys -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ import 'package:nylo_framework/nylo_framework.dart'; diff --git a/LabelStoreMax/lib/config/theme.dart b/LabelStoreMax/lib/config/theme.dart index 844f53a..3cd15f3 100644 --- a/LabelStoreMax/lib/config/theme.dart +++ b/LabelStoreMax/lib/config/theme.dart @@ -6,15 +6,13 @@ import '/resources/themes/styles/color_styles.dart'; import '/resources/themes/styles/dark_theme_colors.dart'; import '/resources/themes/styles/light_theme_colors.dart'; -/* +/* Flutter Themes |-------------------------------------------------------------------------- -| Flutter Themes | Run the below in the terminal to add a new theme. | "dart run nylo_framework:main make:theme bright_theme" | | Learn more: https://nylo.dev/docs/5.20.0/themes-and-styling -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ // App Themes final List> appThemes = [ @@ -30,4 +28,4 @@ final List> appThemes = [ theme: darkTheme, colors: DarkThemeColors(), ), -]; \ No newline at end of file +]; diff --git a/LabelStoreMax/lib/config/toast_notification.dart b/LabelStoreMax/lib/config/toast_notification.dart index b2267e8..63d64d2 100644 --- a/LabelStoreMax/lib/config/toast_notification.dart +++ b/LabelStoreMax/lib/config/toast_notification.dart @@ -2,8 +2,8 @@ import 'package:nylo_framework/nylo_framework.dart'; /// ToastNotificationStyleMetaHelper is used to return /// the correct value for the [ToastNotificationStyleType] toast style. -class NyToastNotificationStyleMetaHelper extends ToastNotificationStyleMetaHelper { - +class NyToastNotificationStyleMetaHelper + extends ToastNotificationStyleMetaHelper { NyToastNotificationStyleMetaHelper(super.style); @override @@ -35,4 +35,4 @@ class NyToastNotificationStyleMetaHelper extends ToastNotificationStyleMetaHelpe // backgroundColor: Colors.Yellow // ); // } -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/config/validation_rules.dart b/LabelStoreMax/lib/config/validation_rules.dart index 5888918..b352a86 100644 --- a/LabelStoreMax/lib/config/validation_rules.dart +++ b/LabelStoreMax/lib/config/validation_rules.dart @@ -1,12 +1,8 @@ - -/* +/* Validation Rules |-------------------------------------------------------------------------- -| Validation Rules -| ------------------------------------------------------------------------- | Add custom validation rules for your project in this file. | Learn more https://nylo.dev/docs/5.20.0/validation#custom-validation-rules -|-------------------------------------------------------------------------- -*/ +|-------------------------------------------------------------------------- */ final Map validationRules = { /// Example @@ -33,4 +29,4 @@ final Map validationRules = { // RegExp regExp = RegExp(r'^(?=.*\d).{4,8}$'); // return regExp.hasMatch(info['data']); // } -// } \ No newline at end of file +// } diff --git a/LabelStoreMax/lib/firebase_options.dart b/LabelStoreMax/lib/firebase_options.dart index d43cba9..fc0576f 100644 --- a/LabelStoreMax/lib/firebase_options.dart +++ b/LabelStoreMax/lib/firebase_options.dart @@ -10,7 +10,7 @@ class DefaultFirebaseOptions { if (kIsWeb) { throw UnsupportedError( 'DefaultFirebaseOptions have not been configured for web - ' - 'you can reconfigure this by running the FlutterFire CLI again.', + 'you can reconfigure this by running the FlutterFire CLI again.', ); } switch (defaultTargetPlatform) { @@ -21,11 +21,15 @@ class DefaultFirebaseOptions { ); } return FirebaseOptions( - apiKey: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['apiKey'], + 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'], + 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) { @@ -36,26 +40,31 @@ class DefaultFirebaseOptions { 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'], + 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.', + '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.', + '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.', + 'you can reconfigure this by running the FlutterFire CLI again.', ); default: throw UnsupportedError( diff --git a/LabelStoreMax/lib/main.dart b/LabelStoreMax/lib/main.dart index 9d74acb..5b0f43e 100644 --- a/LabelStoreMax/lib/main.dart +++ b/LabelStoreMax/lib/main.dart @@ -12,7 +12,10 @@ void main() async { navigatorKey: NyNavigator.instance.router.navigatorKey, onGenerateRoute: nylo.router!.generator(), initialRoute: nylo.getInitialRoute(), + navigatorObservers: [ + ...nylo.getNavigatorObservers(), + ], debugShowCheckedModeBanner: false, ), ); -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/resources/pages/account_delete_page.dart b/LabelStoreMax/lib/resources/pages/account_delete_page.dart index ce5f83c..5c2516a 100644 --- a/LabelStoreMax/lib/resources/pages/account_delete_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_delete_page.dart @@ -9,7 +9,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; +import '/app/events/logout_event.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -28,7 +28,6 @@ class _AccountDeletePageState extends NyState { @override init() async {} - @override Widget build(BuildContext context) { return Scaffold( @@ -76,12 +75,10 @@ class _AccountDeletePageState extends NyState { _deleteAccount() async { await lockRelease('delete_account', perform: () async { - String? userToken = await readAuthToken(); - WPUserDeleteResponse? wpUserDeleteResponse; try { - wpUserDeleteResponse = await WPJsonAPI.instance - .api((request) => request.wpUserDelete(userToken)); + wpUserDeleteResponse = + await WPJsonAPI.instance.api((request) => request.wpUserDelete()); } on Exception catch (e) { NyLogger.error(e.toString()); showToastNotification( @@ -95,7 +92,7 @@ class _AccountDeletePageState extends NyState { if (wpUserDeleteResponse != null) { showToast( title: trans("Success"), description: trans("Account deleted")); - await authLogout(context); + await event(); } }); } diff --git a/LabelStoreMax/lib/resources/pages/account_detail_page.dart b/LabelStoreMax/lib/resources/pages/account_detail_page.dart index 26c1c2c..c3e0023 100644 --- a/LabelStoreMax/lib/resources/pages/account_detail_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_detail_page.dart @@ -10,11 +10,10 @@ import 'package:bubble_tab_indicator/bubble_tab_indicator.dart'; import 'package:flutter/material.dart'; +import '/app/events/logout_event.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/widgets/account_detail_orders_widget.dart'; import '/resources/widgets/account_detail_settings_widget.dart'; -import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -30,27 +29,27 @@ class AccountDetailPage extends StatefulWidget { createState() => _AccountDetailPageState(); } -class _AccountDetailPageState extends State +class _AccountDetailPageState extends NyState with SingleTickerProviderStateMixin { TabController? _tabController; - bool _isLoading = true; int _currentTabIndex = 0; WCCustomerInfoResponse? _wcCustomerInfoResponse; @override - void initState() { - super.initState(); + init() async { _tabController = TabController(vsync: this, length: 2); - _fetchWpUserData(); } - _fetchWpUserData() async { - String? userToken = await readAuthToken(); + @override + boot() async { + await _fetchWpUserData(); + } + _fetchWpUserData() async { WCCustomerInfoResponse? wcCustomerInfoResponse; try { - wcCustomerInfoResponse = await WPJsonAPI.instance - .api((request) => request.wcCustomerInfo(userToken!)); + wcCustomerInfoResponse = + await WPJsonAPI.instance.api((request) => request.wcCustomerInfo()); } on InvalidUserTokenException catch (_) { showToastNotification( context, @@ -58,7 +57,7 @@ class _AccountDetailPageState extends State description: trans("Something went wrong"), style: ToastNotificationStyleType.DANGER, ); - await authLogout(context); + await event(); } on Exception catch (_) { showToastNotification( context, @@ -66,49 +65,16 @@ class _AccountDetailPageState extends State description: trans("Something went wrong"), style: ToastNotificationStyleType.DANGER, ); - } finally { - setState(() { - _isLoading = false; - }); } - if (wcCustomerInfoResponse != null && - wcCustomerInfoResponse.status == 200) { - setState(() { - _wcCustomerInfoResponse = wcCustomerInfoResponse; - }); + if (wcCustomerInfoResponse?.status != 200) { + return; } + _wcCustomerInfoResponse = wcCustomerInfoResponse; } @override - Widget build(BuildContext context) { - Widget? activeBody; - if (_currentTabIndex == 0) { - activeBody = AccountDetailOrdersWidget(); - } else if (_currentTabIndex == 1) { - activeBody = AccountDetailSettingsWidget( - refreshAccount: () { - setState(() { - _isLoading = true; - }); - _fetchWpUserData(); - }, - ); - } - - if (activeBody == null) { - return SizedBox.shrink(); - } - String? userAvatar; - String? userFirstName = ""; - String? userLastName = ""; - if (_wcCustomerInfoResponse != null && - _wcCustomerInfoResponse!.data != null) { - userAvatar = _wcCustomerInfoResponse!.data!.avatar; - - userFirstName = _wcCustomerInfoResponse!.data!.firstName; - userLastName = _wcCustomerInfoResponse!.data!.lastName; - } + Widget view(BuildContext context) { return Scaffold( appBar: AppBar( leading: widget.showLeadingBackButton @@ -125,92 +91,86 @@ class _AccountDetailPageState extends State ), resizeToAvoidBottomInset: false, body: SafeAreaWidget( - child: _isLoading - ? AppLoaderWidget() - : Column( - children: [ - Container( - margin: EdgeInsets.only(top: 10, bottom: 10), - padding: EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Container( - margin: EdgeInsets.only(top: 10), - child: userAvatar != null - ? CircleAvatar( - backgroundImage: NetworkImage(userAvatar), - ) - : Icon( - Icons.account_circle_rounded, - size: 65, - ), - height: 90, - width: 90, - ), - Expanded( - child: Padding( - child: Text( - [userFirstName, userLastName] - .where((t) => (t != null || t != "")) - .toList() - .join(" "), - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - ), - ), - padding: EdgeInsets.only(left: 16), - ), - ), - ], - ), - Padding( - child: TabBar( - tabs: [ - Tab(text: trans("Orders")), - Tab(text: trans("Settings")), - ], - controller: _tabController, - indicatorSize: TabBarIndicatorSize.tab, - labelColor: Colors.white, - unselectedLabelColor: Colors.black87, - indicator: BubbleTabIndicator( - indicatorHeight: 30.0, - indicatorRadius: 5, - indicatorColor: Colors.black87, - tabBarIndicatorSize: TabBarIndicatorSize.tab, - ), - onTap: _tabsTapped, + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 10, bottom: 10), + padding: EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + margin: EdgeInsets.only(top: 10), + child: getAvatar(), + height: 90, + width: 90, + ), + Expanded( + child: Padding( + child: Text( + getFullName(), + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, ), - padding: EdgeInsets.symmetric(vertical: 8), ), - ], + padding: EdgeInsets.only(left: 16), + ), ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - boxShadow: - (Theme.of(context).brightness == Brightness.light) - ? wsBoxShadow() - : null, - color: ThemeColor.get(context).backgroundContainer, + ], + ), + Padding( + child: TabBar( + tabs: [ + Tab(text: trans("Orders")), + Tab(text: trans("Settings")), + ], + controller: _tabController, + indicatorSize: TabBarIndicatorSize.tab, + labelColor: Colors.white, + unselectedLabelColor: Colors.black87, + indicator: BubbleTabIndicator( + indicatorHeight: 30.0, + indicatorRadius: 5, + indicatorColor: Colors.black87, + tabBarIndicatorSize: TabBarIndicatorSize.tab, ), + onTap: _tabsTapped, ), - Expanded(child: activeBody), - ], - ), - ), + padding: EdgeInsets.symmetric(vertical: 8), + ), + ], + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + boxShadow: (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, + color: ThemeColor.get(context).backgroundContainer, + ), + ), + Expanded( + child: NySwitch( + widgets: [ + AccountDetailOrdersWidget(), + AccountDetailSettingsWidget(), + ], + indexSelected: _currentTabIndex, + ), + ), + ], + )), ); } @override void dispose() { - _tabController!.dispose(); + _tabController?.dispose(); super.dispose(); } @@ -219,4 +179,25 @@ class _AccountDetailPageState extends State _currentTabIndex = i; }); } + + String getFullName() { + return [ + _wcCustomerInfoResponse?.data?.firstName, + _wcCustomerInfoResponse?.data?.lastName + ].where((t) => (t != null || t != "")).toList().join(" "); + } + + Widget getAvatar() { + String? avatarUrl = _wcCustomerInfoResponse?.data?.avatar; + if (avatarUrl == null) { + return Icon( + Icons.account_circle_rounded, + size: 65, + ); + } + + return CircleAvatar( + backgroundImage: NetworkImage(avatarUrl), + ); + } } diff --git a/LabelStoreMax/lib/resources/pages/account_landing_page.dart b/LabelStoreMax/lib/resources/pages/account_login_page.dart similarity index 92% rename from LabelStoreMax/lib/resources/pages/account_landing_page.dart rename to LabelStoreMax/lib/resources/pages/account_login_page.dart index c5441d1..5aeafe8 100644 --- a/LabelStoreMax/lib/resources/pages/account_landing_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_login_page.dart @@ -9,10 +9,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/app/models/user.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; +import '/app/events/login_event.dart'; +import '/resources/pages/account_register_page.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/shared_key.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -23,16 +24,16 @@ import 'package:wp_json_api/exceptions/invalid_username_exception.dart'; import 'package:wp_json_api/models/responses/wp_user_login_response.dart'; import 'package:wp_json_api/wp_json_api.dart'; -class AccountLandingPage extends StatefulWidget { - static String path = "/account-landing"; +class AccountLoginPage extends StatefulWidget { + static String path = "/account-login"; final bool showBackButton; - AccountLandingPage({this.showBackButton = true}); + AccountLoginPage({this.showBackButton = true}); @override - createState() => _AccountLandingPageState(); + createState() => _AccountLoginPageState(); } -class _AccountLandingPageState extends NyState { +class _AccountLoginPageState extends NyState { final TextEditingController _tfEmailController = TextEditingController(), _tfPasswordController = TextEditingController(); @@ -125,8 +126,7 @@ class _AccountLandingPageState extends NyState { ) ], ), - onPressed: () => - Navigator.pushNamed(context, "/account-register"), + onPressed: () => routeTo(AccountRegistrationPage.path), ), LinkButton( title: trans("Forgot Password"), @@ -224,10 +224,8 @@ class _AccountLandingPageState extends NyState { if (wpUserLoginResponse.status != 200) { return; } - String? token = wpUserLoginResponse.data!.userToken; - String userId = wpUserLoginResponse.data!.userId.toString(); - User user = User.fromUserAuthResponse(token: token, userId: userId); - await user.save(SharedKey.authUser); + + event(); showToastNotification(context, title: trans("Hello"), diff --git a/LabelStoreMax/lib/resources/pages/account_order_detail_page.dart b/LabelStoreMax/lib/resources/pages/account_order_detail_page.dart index eee1ee3..c547a33 100644 --- a/LabelStoreMax/lib/resources/pages/account_order_detail_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_order_detail_page.dart @@ -10,7 +10,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '/app/controllers/account_order_detail_controller.dart'; import '/bootstrap/helpers.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/woosignal_ui.dart'; @@ -20,10 +19,6 @@ import 'package:woosignal/models/response/order.dart'; class AccountOrderDetailPage extends NyStatefulWidget { static String path = "/account-order-detail"; - @override - final AccountOrderDetailController controller = - AccountOrderDetailController(); - AccountOrderDetailPage({Key? key}) : super(path, key: key, child: _AccountOrderDetailPageState()); } @@ -32,7 +27,6 @@ class _AccountOrderDetailPageState extends NyState { int? _orderId; Order? _order; - @override boot() async { _orderId = widget.controller.data(); @@ -59,162 +53,180 @@ class _AccountOrderDetailPageState extends NyState { resizeToAvoidBottomInset: false, body: SafeAreaWidget( child: afterLoad( - child: () => Column( + child: () => Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(top: 8), + child: Row( crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "${trans("Date Ordered").capitalize()}: ${dateFormatted( + date: _order?.dateCreated ?? "", + formatType: formatForDateTime(FormatType.date), + )}", + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: match( + _order?.status, + () => { + "completed": Colors.green, + "processing": Colors.orange, + "cancelled": Colors.red, + "refunded": Colors.red, + "failed": Colors.red, + "on-hold": Colors.orange, + "pending": Colors.orange, + }, + defaultValue: Colors.grey), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + (_order?.status ?? "").capitalize(), + style: TextStyle( + fontSize: 12, fontWeight: FontWeight.w600), + ), + ) + ], + ).paddingSymmetric(horizontal: 16), + ), + Container( + margin: EdgeInsets.only(top: 10, bottom: 10), + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: EdgeInsets.only(top: 8), + Flexible( + child: Text("${trans("Ships to").capitalize()}:"), + ), + Flexible( child: Text( - "${trans("Date Ordered").capitalize()}: ${dateFormatted( - date: _order?.dateCreated ?? "", - formatType: formatForDateTime(FormatType.date), - )}", + [ + [ + _order?.shipping?.firstName, + _order?.shipping?.lastName + ].where((t) => t != null).toList().join(" "), + _order?.shipping?.address1, + _order?.shipping?.address2, + _order?.shipping?.city, + _order?.shipping?.state, + _order?.shipping?.postcode, + _order?.shipping?.country, + ] + .where((t) => (t != "" && t != null)) + .toList() + .join("\n"), + textAlign: TextAlign.right, ), ), - Container( - margin: EdgeInsets.only(top: 10, bottom: 10), - padding: - EdgeInsets.symmetric(horizontal: 16, vertical: 16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text("${trans("Ships to").capitalize()}:"), - ), - Flexible( - child: Text( - [ - [ - _order!.shipping!.firstName, - _order!.shipping!.lastName - ].where((t) => t != null).toList().join(" "), - _order!.shipping!.address1, - _order!.shipping!.address2, - _order!.shipping!.city, - _order!.shipping!.state, - _order!.shipping!.postcode, - _order!.shipping!.country, - ] - .where((t) => (t != "" && t != null)) - .toList() - .join("\n"), - textAlign: TextAlign.right, + ], + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + boxShadow: (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, + color: (Theme.of(context).brightness == Brightness.light) + ? Colors.white + : Color(0xFF2C2C2C), + ), + ), + Expanded( + child: ListView.builder( + itemBuilder: (cxt, i) { + LineItems lineItem = _order!.lineItems![i]; + return Card( + child: ListTile( + contentPadding: EdgeInsets.only( + top: 5, bottom: 5, left: 8, right: 6), + title: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Color(0xFFFCFCFC), width: 1), ), ), - ], - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - boxShadow: - (Theme.of(context).brightness == Brightness.light) - ? wsBoxShadow() - : null, - color: - (Theme.of(context).brightness == Brightness.light) - ? Colors.white - : Color(0xFF2C2C2C), - ), - ), - Expanded( - child: ListView.builder( - itemBuilder: (cxt, i) { - LineItems lineItem = _order!.lineItems![i]; - return Card( - child: ListTile( - contentPadding: EdgeInsets.only( - top: 5, bottom: 5, left: 8, right: 6), - title: Container( - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Color(0xFFFCFCFC), width: 1), - ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Text( + lineItem.name!, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text( - lineItem.name!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - Container( - width: 70, - alignment: Alignment.topRight, - child: Text( - formatStringCurrency( - total: lineItem.total) - .capitalize(), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.bold), - ), - ), - ], + ), + Container( + width: 70, + alignment: Alignment.topRight, + child: Text( + formatStringCurrency(total: lineItem.total) + .capitalize(), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontWeight: FontWeight.bold), ), ), - subtitle: Container( - decoration: BoxDecoration( - border: Border( - top: BorderSide( - color: Colors.grey[100]!))), - padding: const EdgeInsets.only(top: 10), - margin: EdgeInsets.only(top: 4), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Text( - formatStringCurrency( - total: lineItem.price, - ), - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - fontWeight: FontWeight.w600, - ), - textAlign: TextAlign.left, - ), - Text( - "x ${lineItem.quantity.toString()}", - style: Theme.of(context) - .textTheme - .bodyLarge, - textAlign: TextAlign.left, - ), - ], + ], + ), + ), + subtitle: Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(color: Colors.grey[100]!))), + padding: const EdgeInsets.only(top: 10), + margin: EdgeInsets.only(top: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + formatStringCurrency( + total: lineItem.price, ), - ], - ), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith( + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.left, + ), + Text( + "x ${lineItem.quantity.toString()}", + style: + Theme.of(context).textTheme.bodyLarge, + textAlign: TextAlign.left, + ), + ], ), - ), - ); - }, - itemCount: _order?.lineItems?.length ?? 0, + ], + ), + ), ), - ), - ], - )), + ); + }, + itemCount: _order?.lineItems?.length ?? 0, + ), + ), + ], + ), + ), ), ); } - _fetchOrder() async { _order = await (appWooSignal((api) => api.retrieveOrder(_orderId!))); } diff --git a/LabelStoreMax/lib/resources/pages/account_profile_update_page.dart b/LabelStoreMax/lib/resources/pages/account_profile_update_page.dart index 2bad343..67e2067 100644 --- a/LabelStoreMax/lib/resources/pages/account_profile_update_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_profile_update_page.dart @@ -9,8 +9,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; -import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -23,142 +21,125 @@ class AccountProfileUpdatePage extends StatefulWidget { AccountProfileUpdatePage(); @override - createState() => - _AccountProfileUpdatePageState(); + createState() => _AccountProfileUpdatePageState(); } -class _AccountProfileUpdatePageState extends State { +class _AccountProfileUpdatePageState extends NyState { _AccountProfileUpdatePageState(); - bool isLoading = true; final TextEditingController _tfFirstName = TextEditingController(), _tfLastName = TextEditingController(); @override - void dispose() { - super.dispose(); - } - - @override - void initState() { - super.initState(); - _fetchUserDetails(); + boot() async { + await _fetchUserDetails(); } _fetchUserDetails() async { WPUserInfoResponse wpUserInfoResponse = await WPJsonAPI.instance.api((request) async { - return request.wpGetUserInfo((await readAuthToken()) ?? "0"); + return request.wpGetUserInfo(); }); _tfFirstName.text = wpUserInfoResponse.data!.firstName!; _tfLastName.text = wpUserInfoResponse.data!.lastName!; - setState(() { - isLoading = false; - }); } @override - Widget build(BuildContext context) { + Widget view(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text( - trans("Update Details"), - style: TextStyle( - fontSize: 20, + appBar: AppBar( + title: Text( + trans("Update Details"), + style: TextStyle( + fontSize: 20, + ), ), + centerTitle: true, + elevation: 1, ), - centerTitle: true, - elevation: 1, - ), - body: isLoading - ? AppLoaderWidget() - : SafeArea( - child: Column( - children: [ - Expanded( - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Flexible( - child: Row( - children: [ - Flexible( - child: TextEditingRow( - heading: trans("First Name"), - controller: _tfFirstName, - keyboardType: TextInputType.text, - ), - ), - Flexible( - child: TextEditingRow( - heading: trans("Last Name"), - controller: _tfLastName, - keyboardType: TextInputType.text, - ), - ), - ], + body: SafeArea( + child: Column( + children: [ + Expanded( + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Flexible( + child: Row( + children: [ + Flexible( + child: TextEditingRow( + heading: trans("First Name"), + controller: _tfFirstName, + keyboardType: TextInputType.text, + ), + ), + Flexible( + child: TextEditingRow( + heading: trans("Last Name"), + controller: _tfLastName, + keyboardType: TextInputType.text, + ), ), - ), - Padding( - padding: EdgeInsets.only(top: 5), - ), - Padding( - padding: EdgeInsets.only(top: 10), - ), - PrimaryButton( - title: trans("Update Details"), - isLoading: isLoading, - action: _updateDetails, - ) - ], + ], + ), ), - margin: EdgeInsets.all(8), - padding: EdgeInsets.all(8), - ), + Padding( + padding: EdgeInsets.only(top: 5), + ), + Padding( + padding: EdgeInsets.only(top: 10), + ), + PrimaryButton( + title: trans("Update Details"), + isLoading: isLocked('update_account'), + action: _updateDetails, + ) + ], ), - ], + margin: EdgeInsets.all(8), + padding: EdgeInsets.all(8), + ), ), - ), - ); + ], + ), + )); } _updateDetails() async { String firstName = _tfFirstName.text; String lastName = _tfLastName.text; - if (isLoading == false) { - setState(() { - isLoading = true; - }); - - String? userToken = await readAuthToken(); - WPUserInfoUpdatedResponse? wpUserInfoUpdatedResponse; - try { - wpUserInfoUpdatedResponse = await WPJsonAPI.instance.api((request) => - request.wpUpdateUserInfo(userToken, - firstName: firstName, lastName: lastName)); - } on Exception catch (_) { - showToastNotification(context, - title: trans("Invalid details"), - description: trans("Please check your email and password"), - style: ToastNotificationStyleType.DANGER); - } finally { - setState(() { - isLoading = false; - }); - } + validate( + rules: { + "first_name": [firstName, "not_empty"], + "last_name": [lastName, "not_empty"] + }, + onSuccess: () async { + WPUserInfoUpdatedResponse? wpUserInfoUpdatedResponse; + try { + wpUserInfoUpdatedResponse = await WPJsonAPI.instance.api( + (request) => request.wpUpdateUserInfo( + firstName: firstName, lastName: lastName)); + } on Exception catch (_) { + showToastNotification(context, + title: trans("Invalid details"), + description: trans("Please check your email and password"), + style: ToastNotificationStyleType.DANGER); + } - if (wpUserInfoUpdatedResponse != null && - wpUserInfoUpdatedResponse.status == 200) { - showToastNotification(context, - title: trans("Success"), - description: trans("Account updated"), - style: ToastNotificationStyleType.SUCCESS); - Navigator.pop(context); - } - } + if (wpUserInfoUpdatedResponse != null && + wpUserInfoUpdatedResponse.status == 200) { + showToastNotification(context, + title: trans("Success"), + description: trans("Account updated"), + style: ToastNotificationStyleType.SUCCESS); + Navigator.pop(context); + } + }, + lockRelease: "update_account"); } } diff --git a/LabelStoreMax/lib/resources/pages/account_register_page.dart b/LabelStoreMax/lib/resources/pages/account_register_page.dart index c002672..663d518 100644 --- a/LabelStoreMax/lib/resources/pages/account_register_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_register_page.dart @@ -8,13 +8,10 @@ // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -import 'dart:math'; - import 'package:flutter/material.dart'; -import '/app/models/user.dart'; +import '/app/events/login_event.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/shared_key.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/woosignal_ui.dart'; @@ -34,8 +31,7 @@ class AccountRegistrationPage extends StatefulWidget { AccountRegistrationPage(); @override - createState() => - _AccountRegistrationPageState(); + createState() => _AccountRegistrationPageState(); } class _AccountRegistrationPageState extends NyState { @@ -166,27 +162,18 @@ class _AccountRegistrationPageState extends NyState { } await lockRelease('register_user', perform: () async { - String username = - (email.replaceAll(RegExp(r'([@.])'), "")) + _randomStr(4); - WPUserRegisterResponse? wpUserRegisterResponse; try { wpUserRegisterResponse = await WPJsonAPI.instance.api( - (request) => request.wpRegister( + (request) => request.wcRegister( email: email.toLowerCase(), password: password, - username: username, + args: { + "first_name": firstName, + "last_name": lastName, + }, ), ); - - if (wpUserRegisterResponse?.data?.userToken != null) { - await WPJsonAPI.instance.api((request) => request.wpUserAddRole( - wpUserRegisterResponse!.data!.userToken, - role: "customer")); - await WPJsonAPI.instance.api((request) => request.wpUserRemoveRole( - wpUserRegisterResponse!.data!.userToken, - role: "subscriber")); - } } on UsernameTakenException catch (e) { showToastNotification(context, title: trans("Oops!"), @@ -233,14 +220,7 @@ class _AccountRegistrationPageState extends NyState { return; } - // Save user to shared preferences - String? token = wpUserRegisterResponse.data!.userToken; - String userId = wpUserRegisterResponse.data!.userId.toString(); - User user = User.fromUserAuthResponse(token: token, userId: userId); - await user.save(SharedKey.authUser); - - await WPJsonAPI.instance.api((request) => request.wpUpdateUserInfo(token, - firstName: firstName, lastName: lastName)); + event(); showToastNotification(context, title: "${trans("Hello")} $firstName", @@ -269,9 +249,7 @@ class _AccountRegistrationPageState extends NyState { ), Divider(), TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, + onPressed: pop, child: Text('Close'), ), ], @@ -279,16 +257,6 @@ class _AccountRegistrationPageState extends NyState { ); } - String _randomStr(int strLen) { - const chars = "abcdefghijklmnopqrstuvwxyz0123456789"; - Random rnd = Random(DateTime.now().millisecondsSinceEpoch); - String result = ""; - for (var i = 0; i < strLen; i++) { - result += chars[rnd.nextInt(chars.length)]; - } - return result; - } - void _viewTermsConditions() { Navigator.pop(context); openBrowserTab(url: _wooSignalApp!.appTermsLink!); diff --git a/LabelStoreMax/lib/resources/pages/account_shipping_details_page.dart b/LabelStoreMax/lib/resources/pages/account_shipping_details_page.dart index 4e666b8..84e893e 100644 --- a/LabelStoreMax/lib/resources/pages/account_shipping_details_page.dart +++ b/LabelStoreMax/lib/resources/pages/account_shipping_details_page.dart @@ -9,12 +9,12 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/customer_countries_page.dart'; import '/app/models/billing_details.dart'; import '/app/models/customer_address.dart'; import '/app/models/customer_country.dart'; import '/app/models/default_shipping.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/customer_address_input.dart'; @@ -32,8 +32,7 @@ class AccountShippingDetailsPage extends StatefulWidget { AccountShippingDetailsPage(); @override - createState() => - _AccountShippingDetailsPageState(); + createState() => _AccountShippingDetailsPageState(); } class _AccountShippingDetailsPageState @@ -85,12 +84,8 @@ class _AccountShippingDetailsPageState ); @override - init() async { - super.init(); - - await awaitData(perform: () async { - await _fetchUserDetails(); - }); + boot() async { + await _fetchUserDetails(); } _setFieldsFromCustomerAddress(CustomerAddress? customerAddress, @@ -275,12 +270,10 @@ class _AccountShippingDetailsPageState customerCountry: _shippingCountry, ); - String? userToken = await readAuthToken(); - WPUserInfoUpdatedResponse? wpUserInfoUpdatedResponse; try { wpUserInfoUpdatedResponse = await WPJsonAPI.instance.api( - (request) => request.wpUpdateUserInfo(userToken, metaData: [ + (request) => request.wpUpdateUserInfo(metaData: [ ...userBillingAddress.toUserMetaDataItem('billing'), ...userShippingAddress.toUserMetaDataItem('shipping'), ]), @@ -327,7 +320,7 @@ class _AccountShippingDetailsPageState } _navigateToSelectCountry({required String type}) { - Navigator.pushNamed(context, "/customer-countries").then((value) { + routeTo(CustomerCountriesPage.path, onPop: (value) { if (value == null) { return; } @@ -346,12 +339,10 @@ class _AccountShippingDetailsPageState } _fetchUserDetails() async { - String? userToken = await readAuthToken(); - WPUserInfoResponse? wpUserInfoResponse; try { - wpUserInfoResponse = await WPJsonAPI.instance - .api((request) => request.wpGetUserInfo(userToken!)); + wpUserInfoResponse = + await WPJsonAPI.instance.api((request) => request.wpGetUserInfo()); } on Exception catch (e) { print(e.toString()); showToastNotification( @@ -371,8 +362,6 @@ class _AccountShippingDetailsPageState type: "shipping"); _setFieldsFromCustomerAddress(billingDetails.billingAddress, type: "billing"); - - setState(() {}); } } } diff --git a/LabelStoreMax/lib/resources/pages/browse_category_page.dart b/LabelStoreMax/lib/resources/pages/browse_category_page.dart index 96c0a55..d5269bc 100644 --- a/LabelStoreMax/lib/resources/pages/browse_category_page.dart +++ b/LabelStoreMax/lib/resources/pages/browse_category_page.dart @@ -10,25 +10,20 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '/app/controllers/product_category_search_loader_controller.dart'; -import '/app/controllers/browse_category_controller.dart'; +import '/resources/widgets/product_item_container_widget.dart'; +import '/resources/pages/product_detail_page.dart'; import '/bootstrap/enums/sort_enums.dart'; import '/bootstrap/helpers.dart'; -import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/product.dart' as ws_product; class BrowseCategoryPage extends NyStatefulWidget { static String path = "/browse-category"; - @override - final BrowseCategoryController controller = BrowseCategoryController(); - BrowseCategoryPage({Key? key}) : super(path, key: key, child: _BrowseCategoryPageState()); } @@ -37,22 +32,13 @@ class _BrowseCategoryPageState extends NyState { ProductCategory? productCategory; _BrowseCategoryPageState(); - final RefreshController _refreshController = - RefreshController(initialRefresh: false); - final ProductCategorySearchLoaderController - _productCategorySearchLoaderController = - ProductCategorySearchLoaderController(); - - bool _shouldStopRequests = false; - bool _isLoading = true; + SortByType? _sortByType; @override init() async { productCategory = widget.controller.data(); - await fetchProducts(); } - @override Widget build(BuildContext context) { return Scaffold( @@ -77,48 +63,37 @@ class _BrowseCategoryPageState extends NyState { ], ), body: SafeAreaWidget( - child: _isLoading - ? Center( - child: AppLoaderWidget(), - ) - : refreshableScroll( - context, - refreshController: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - products: _productCategorySearchLoaderController.getResults(), - onTap: _showProduct, - ), - ), + child: NyPullToRefresh.grid( + data: (page) async { + List products = + await appWooSignal((api) => api.getProducts( + perPage: 25, + category: productCategory?.id.toString(), + page: page, + status: "publish", + stockStatus: "instock", + )); + return products; + }, + child: (context, product) { + return Container( + height: 300, + child: ProductItemContainer( + product: product, + onTap: () => _showProduct(product), + ), + ); + }, + stateName: 'browse_category_pull_to_refresh', + sort: (products) { + return _sortProducts(products, + by: _sortByType ?? SortByType.dateDesc); + }, + )), ); } - void _onRefresh() async { - _productCategorySearchLoaderController.clear(); - await fetchProducts(); - - setState(() { - _shouldStopRequests = false; - _refreshController.refreshCompleted(resetFooterState: true); - }); - } - - void _onLoading() async { - await fetchProducts(); - - if (mounted) { - setState(() {}); - if (_shouldStopRequests) { - _refreshController.loadNoData(); - } else { - _refreshController.loadComplete(); - } - } - } - - _sortProducts({required SortByType by}) { - List products = - _productCategorySearchLoaderController.getResults(); + _sortProducts(List products, {required SortByType by}) { switch (by) { case SortByType.lowToHigh: products.sort( @@ -142,10 +117,21 @@ class _BrowseCategoryPageState extends NyState { (product1, product2) => product2.name!.compareTo(product1.name!), ); break; + case SortByType.dateAsc: + products.sort((product1, product2) { + DateTime? date1 = product1.dateCreated.toDateTime(); + DateTime? date2 = product2.dateCreated.toDateTime(); + return date1.compareTo(date2); + }); + case SortByType.dateDesc: + products.sort((product1, product2) { + DateTime? date1 = product1.dateCreated.toDateTime(); + DateTime? date2 = product2.dateCreated.toDateTime(); + return date2.compareTo(date1); + }); + break; } - setState(() { - Navigator.pop(context); - }); + return products; } _modalSheetTune() { @@ -153,63 +139,92 @@ class _BrowseCategoryPageState extends NyState { context, title: trans("Sort results"), bodyWidget: ListView( - children: [ + children: [ LinkButton( title: trans("Sort: Low to high"), - action: () => _sortProducts(by: SortByType.lowToHigh), + selected: _sortByType == SortByType.lowToHigh, + action: () { + _sortByType = SortByType.lowToHigh; + StateAction.refreshPage('browse_category_pull_to_refresh', + setState: () {}); + pop(); + }, ), Divider( height: 0, ), LinkButton( title: trans("Sort: High to low"), - action: () => _sortProducts(by: SortByType.highToLow), + selected: _sortByType == SortByType.highToLow, + action: () { + _sortByType = SortByType.highToLow; + StateAction.refreshPage('browse_category_pull_to_refresh', + setState: () {}); + pop(); + }, ), Divider( height: 0, ), LinkButton( title: trans("Sort: Name A-Z"), - action: () => _sortProducts(by: SortByType.nameAZ), + selected: _sortByType == SortByType.nameAZ, + action: () { + _sortByType = SortByType.nameAZ; + StateAction.refreshPage('browse_category_pull_to_refresh', + setState: () {}); + pop(); + }, ), Divider( height: 0, ), LinkButton( title: trans("Sort: Name Z-A"), - action: () => _sortProducts(by: SortByType.nameZA), + selected: _sortByType == SortByType.nameZA, + action: () { + _sortByType = SortByType.nameZA; + StateAction.refreshPage('browse_category_pull_to_refresh', + setState: () {}); + pop(); + }, ), Divider( height: 0, ), - LinkButton(title: trans("Cancel"), action: _dismissModal) + LinkButton( + title: trans("Sort: Date New to Old"), + selected: _sortByType == SortByType.dateDesc, + action: () { + _sortByType = SortByType.dateDesc; + StateAction.refreshPage('browse_category_pull_to_refresh', + setState: () {}); + pop(); + }, + ), + Divider( + height: 0, + ), + LinkButton( + title: trans("Sort: Date Old to New"), + selected: _sortByType == SortByType.dateAsc, + action: () { + _sortByType = SortByType.dateAsc; + StateAction.refreshPage('browse_category_pull_to_refresh', + setState: () {}); + pop(); + }, + ), + Divider( + height: 0, + ), + LinkButton(title: trans("Cancel"), action: pop) ], ), ); } - Future fetchProducts() async { - await _productCategorySearchLoaderController.loadProducts( - hasResults: (result) { - if (result == false) { - setState(() { - _isLoading = false; - _shouldStopRequests = true; - }); - return false; - } - return true; - }, - didFinish: () => setState(() { - _isLoading = false; - }), - productCategory: productCategory, - ); - } - - _dismissModal() => Navigator.pop(context); - _showProduct(ws_product.Product product) { - Navigator.pushNamed(context, "/product-detail", arguments: product); + routeTo(ProductDetailPage.path, data: product); } } diff --git a/LabelStoreMax/lib/resources/pages/browse_search_page.dart b/LabelStoreMax/lib/resources/pages/browse_search_page.dart index c69fb95..af1c921 100644 --- a/LabelStoreMax/lib/resources/pages/browse_search_page.dart +++ b/LabelStoreMax/lib/resources/pages/browse_search_page.dart @@ -10,41 +10,28 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '/app/controllers/browse_search_controller.dart'; -import '/app/controllers/product_search_loader_controller.dart'; +import '/resources/widgets/product_item_container_widget.dart'; import '/bootstrap/helpers.dart'; -import '/resources/widgets/app_loader_widget.dart'; +import '/resources/pages/product_detail_page.dart'; import '/resources/widgets/safearea_widget.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:woosignal/models/response/product.dart' as ws_product; class BrowseSearchPage extends NyStatefulWidget { static String path = "/product-search"; - @override - final BrowseSearchController controller = BrowseSearchController(); - BrowseSearchPage({Key? key}) : super(path, key: key, child: _BrowseSearchState()); } class _BrowseSearchState extends NyState { - final RefreshController _refreshController = - RefreshController(initialRefresh: false); - final ProductSearchLoaderController _productSearchLoaderController = - ProductSearchLoaderController(); - String? _search; - bool _shouldStopRequests = false, _isLoading = true; @override init() async { _search = widget.controller.data(); - await fetchProducts(); } - @override Widget build(BuildContext context) { return Scaffold( @@ -63,65 +50,26 @@ class _BrowseSearchState extends NyState { centerTitle: true, ), body: SafeAreaWidget( - child: _isLoading - ? Center( - child: AppLoaderWidget(), - ) - : refreshableScroll( - context, - refreshController: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - products: _productSearchLoaderController.getResults(), - onTap: _showProduct, - ), - ), - ); - } - - void _onRefresh() async { - _productSearchLoaderController.clear(); - await fetchProducts(); - - setState(() { - _shouldStopRequests = false; - _refreshController.refreshCompleted(resetFooterState: true); - }); - } - - void _onLoading() async { - await fetchProducts(); - - if (mounted) { - setState(() {}); - if (_shouldStopRequests) { - _refreshController.loadNoData(); - } else { - _refreshController.loadComplete(); - } - } - } - - Future fetchProducts() async { - await _productSearchLoaderController.loadProducts( - hasResults: (result) { - if (result == false) { - setState(() { - _isLoading = false; - _shouldStopRequests = true; - }); - return false; - } - return true; - }, - didFinish: () => setState(() { - _isLoading = false; - }), - search: _search, + child: NyPullToRefresh.grid(child: (context, product) { + product as ws_product.Product; + return Container( + height: 300, + child: ProductItemContainer( + product: product, + onTap: () { + routeTo(ProductDetailPage.path, data: product); + }, + ), + ); + }, data: (page) { + return appWooSignal((api) => api.getProducts( + perPage: 100, + search: _search, + page: page, + status: "publish", + stockStatus: "instock", + )); + })), ); } - - _showProduct(ws_product.Product product) { - Navigator.pushNamed(context, "/product-detail", arguments: product); - } } diff --git a/LabelStoreMax/lib/resources/pages/cart_page.dart b/LabelStoreMax/lib/resources/pages/cart_page.dart index 2795b07..0dfcddb 100644 --- a/LabelStoreMax/lib/resources/pages/cart_page.dart +++ b/LabelStoreMax/lib/resources/pages/cart_page.dart @@ -9,19 +9,19 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import 'package:flutter_app/resources/pages/account_landing_page.dart'; -import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart'; +import 'package:flutter_app/resources/widgets/cart_item_container_widget.dart'; +import '/resources/pages/account_login_page.dart'; +import '/resources/pages/checkout_confirmation_page.dart'; +import 'package:wp_json_api/wp_json_api.dart'; import '/app/models/cart.dart'; import '/app/models/cart_line_item.dart'; import '/app/models/checkout_session.dart'; import '/app/models/customer_address.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/text_row_widget.dart'; -import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; class CartPage extends StatefulWidget { @@ -104,7 +104,7 @@ class _CartPageState extends NyState { sfCustomerAddress; } - if (!(await authCheck())) { + if (!(await WPJsonAPI.wpUserLoggedIn())) { // show modal to ask customer if they would like to checkout as guest or login showAdaptiveDialog( context: context, @@ -121,14 +121,15 @@ class _CartPageState extends NyState { child: Text("Checkout as guest".tr()), ), if (AppHelper.instance.appConfig!.wpLoginEnabled == 1) - TextButton( - onPressed: () { - Navigator.pop(context); - UserAuth.instance.redirect = CheckoutConfirmationPage.path; - routeTo(AccountLandingPage.path); - }, - child: Text("Login / Create an account".tr()), - ), + TextButton( + onPressed: () { + Navigator.pop(context); + UserAuth.instance.redirect = + CheckoutConfirmationPage.path; + routeTo(AccountLoginPage.path); + }, + child: Text("Login / Create an account".tr()), + ), TextButton( onPressed: () => Navigator.pop(context), child: Text("Cancel".tr()), diff --git a/LabelStoreMax/lib/resources/pages/checkout_confirmation_page.dart b/LabelStoreMax/lib/resources/pages/checkout_confirmation_page.dart index 54836d0..09acfe3 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_confirmation_page.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_confirmation_page.dart @@ -31,20 +31,19 @@ import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; -class CheckoutConfirmationPage extends StatefulWidget { +class CheckoutConfirmationPage extends NyStatefulWidget { static String path = '/checkout'; - CheckoutConfirmationPage({super.key}); + CheckoutConfirmationPage({super.key}) : super(path); @override - createState() => - CheckoutConfirmationPageState(); + createState() => CheckoutConfirmationPageState(); } class CheckoutConfirmationPageState extends NyState { CheckoutConfirmationPageState(); - bool _showFullLoader = true, _isProcessingPayment = false; - final List _taxRates = []; + bool _showFullLoader = false; + List _taxRates = []; TaxRate? _taxRate; final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig; @@ -80,6 +79,7 @@ class CheckoutConfirmationPageState extends NyState { } _getTaxes() async { + _taxRates = []; int pageIndex = 1; bool fetchMore = true; while (fetchMore == true) { @@ -95,19 +95,15 @@ class CheckoutConfirmationPageState extends NyState { fetchMore = false; } } + } + _getUserTax() { if (_taxRates.isEmpty) { - setState(() { - _showFullLoader = false; - }); return; } if (CheckoutSession.getInstance.billingDetails == null || CheckoutSession.getInstance.billingDetails!.shippingAddress == null) { - setState(() { - _showFullLoader = false; - }); return; } CustomerCountry? shippingCountry = CheckoutSession @@ -116,8 +112,6 @@ class CheckoutConfirmationPageState extends NyState { CheckoutSession.getInstance.billingDetails!.shippingAddress!.postalCode; if (shippingCountry == null) { - _showFullLoader = false; - setState(() {}); return; } @@ -159,9 +153,6 @@ class CheckoutConfirmationPageState extends NyState { if (taxRate != null) { _taxRate = taxRate; } - setState(() { - _showFullLoader = false; - }); } @override @@ -225,35 +216,25 @@ class CheckoutConfirmationPageState extends NyState { CheckoutUserDetailsWidget( context: context, checkoutSession: checkoutSession, - resetState: () { - setState(() { - _showFullLoader = true; - }); - _getTaxes(); - }, ), CheckoutPaymentTypeWidget( context: context, checkoutSession: checkoutSession, - resetState: () => setState(() {}), ), CheckoutShippingTypeWidget( context: context, checkoutSession: checkoutSession, - resetState: () => setState(() {}), wooSignalApp: _wooSignalApp, ), if (_wooSignalApp!.couponEnabled == true) CheckoutSelectCouponWidget( context: context, checkoutSession: checkoutSession, - resetState: () => setState(() {}), ), Container( decoration: BoxDecoration( boxShadow: wsBoxShadow(), color: Colors.white, - // borderRadius: BorderRadius.circular(16) ), padding: EdgeInsets.symmetric(vertical: 16), margin: EdgeInsets.only(top: 20), @@ -297,46 +278,47 @@ class CheckoutConfirmationPageState extends NyState { padding: EdgeInsets.only(top: 8, left: 8, right: 8)), Padding( - padding: EdgeInsets.symmetric(horizontal: 8), - child: RichText( - textAlign: TextAlign.left, - text: TextSpan( - text: - '${trans('By completing this order, I agree to all')} ', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontSize: 12, - ), - children: [ - TextSpan( - recognizer: TapGestureRecognizer() - ..onTap = _openTermsLink, - text: trans("Terms and conditions") - .toLowerCase(), - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: ThemeColor.get(context) - .primaryAccent, - fontSize: 12, - ), - ), - TextSpan( - text: ".", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: Colors.black87, - fontSize: 12, - ), + padding: EdgeInsets.symmetric(horizontal: 8), + child: RichText( + textAlign: TextAlign.left, + text: TextSpan( + text: + '${trans('By completing this order, I agree to all')} ', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + fontSize: 12, ), - ], - ), - )), + children: [ + TextSpan( + recognizer: TapGestureRecognizer() + ..onTap = _openTermsLink, + text: trans("Terms and conditions") + .toLowerCase(), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: ThemeColor.get(context) + .primaryAccent, + fontSize: 12, + ), + ), + TextSpan( + text: ".", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: Colors.black87, + fontSize: 12, + ), + ), + ], + ), + ), + ), ], ), ], @@ -352,10 +334,13 @@ class CheckoutConfirmationPageState extends NyState { CheckoutTotal(title: trans("Total"), taxRate: _taxRate), Padding(padding: EdgeInsets.only(bottom: 8)), PrimaryButton( - title: _isProcessingPayment - ? "${trans("PROCESSING")}..." - : trans("CHECKOUT"), - action: _isProcessingPayment ? null : _handleCheckout, + isLoading: isLocked('payment'), + title: trans("CHECKOUT"), + action: () async { + lockRelease('payment', perform: () async { + await _handleCheckout(); + }); + }, ), ], ), @@ -371,6 +356,8 @@ class CheckoutConfirmationPageState extends NyState { openBrowserTab(url: AppHelper.instance.appConfig?.appTermsLink ?? ""); _handleCheckout() async { + _getUserTax(); + CheckoutSession checkoutSession = CheckoutSession.getInstance; if (checkoutSession.billingDetails!.billingAddress == null) { showToastNotification( @@ -450,23 +437,10 @@ class CheckoutConfirmationPageState extends NyState { return; } - if (_isProcessingPayment == true) { - return; - } - - setState(() { - _isProcessingPayment = true; - }); - try { - await checkoutSession.paymentType! - .pay(context, state: this, taxRate: _taxRate); + await checkoutSession.paymentType!.pay(context, taxRate: _taxRate); } on Exception catch (e) { print(e.toString()); } - - setState(() { - _isProcessingPayment = false; - }); } } diff --git a/LabelStoreMax/lib/resources/pages/checkout_details_page.dart b/LabelStoreMax/lib/resources/pages/checkout_details_page.dart index bff2594..0cacdcf 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_details_page.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_details_page.dart @@ -9,13 +9,13 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/customer_countries_page.dart'; import '/app/models/billing_details.dart'; import '/app/models/checkout_session.dart'; import '/app/models/customer_address.dart'; import '/app/models/customer_country.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/customer_address_input.dart'; @@ -95,7 +95,7 @@ class _CheckoutDetailsPageState extends NyState { _wpLoginEnabled = AppHelper.instance.appConfig?.wpLoginEnabled == 1; - if (_wpLoginEnabled == true) { + if (_wpLoginEnabled == true && (await WPJsonAPI.wpUserLoggedIn())) { await awaitData(perform: () async { await _fetchUserDetails(); }); @@ -391,12 +391,10 @@ class _CheckoutDetailsPageState extends NyState { } // Update WP shipping info for user - if (_wpLoginEnabled == true) { - String? userToken = await readAuthToken(); - + if (_wpLoginEnabled == true && (await WPJsonAPI.wpUserLoggedIn())) { try { await WPJsonAPI.instance.api( - (request) => request.wpUpdateUserInfo(userToken, metaData: [ + (request) => request.wpUpdateUserInfo(metaData: [ ...?billingDetails.billingAddress?.toUserMetaDataItem('billing'), ...?billingDetails.shippingAddress ?.toUserMetaDataItem('shipping'), @@ -476,7 +474,7 @@ class _CheckoutDetailsPageState extends NyState { } _navigateToSelectCountry({required String type}) { - Navigator.pushNamed(context, "/customer-countries").then((value) { + routeTo(CustomerCountriesPage.path, onPop: (value) { if (value == null) { return; } @@ -495,12 +493,10 @@ class _CheckoutDetailsPageState extends NyState { _fetchUserDetails() async { await lockRelease('load_shipping_info', perform: () async { - String? userToken = await readAuthToken(); - WPUserInfoResponse? wpUserInfoResponse; try { - wpUserInfoResponse = await WPJsonAPI.instance - .api((request) => request.wpGetUserInfo(userToken!)); + wpUserInfoResponse = + await WPJsonAPI.instance.api((request) => request.wpGetUserInfo()); } on Exception catch (e) { print(e.toString()); showToastNotification( diff --git a/LabelStoreMax/lib/resources/pages/checkout_payment_type_page.dart b/LabelStoreMax/lib/resources/pages/checkout_payment_type_page.dart index 8fdbac3..b03cf52 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_payment_type_page.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_payment_type_page.dart @@ -22,8 +22,7 @@ class CheckoutPaymentTypePage extends StatefulWidget { CheckoutPaymentTypePage(); @override - createState() => - _CheckoutPaymentTypePageState(); + createState() => _CheckoutPaymentTypePageState(); } class _CheckoutPaymentTypePageState extends NyState { diff --git a/LabelStoreMax/lib/resources/pages/checkout_shipping_type_page.dart b/LabelStoreMax/lib/resources/pages/checkout_shipping_type_page.dart index ee3a1f6..19070d6 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_shipping_type_page.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_shipping_type_page.dart @@ -29,8 +29,7 @@ class CheckoutShippingTypePage extends StatefulWidget { CheckoutShippingTypePage(); @override - createState() => - _CheckoutShippingTypePageState(); + createState() => _CheckoutShippingTypePageState(); } class _CheckoutShippingTypePageState extends State { diff --git a/LabelStoreMax/lib/resources/pages/checkout_status_page.dart b/LabelStoreMax/lib/resources/pages/checkout_status_page.dart index 6d5593b..9c9cc8e 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_status_page.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_status_page.dart @@ -9,7 +9,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/app/controllers/checkout_status_controller.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; import '/app/models/cart.dart'; import '/app/models/checkout_session.dart'; import '/bootstrap/helpers.dart'; @@ -21,9 +21,6 @@ import '../widgets/woosignal_ui.dart'; class CheckoutStatusPage extends NyStatefulWidget { static String path = "/checkout-status"; - @override - final CheckoutStatusController controller = CheckoutStatusController(); - CheckoutStatusPage({Key? key}) : super(path, key: key, child: _CheckoutStatusState()); } @@ -176,8 +173,9 @@ class _CheckoutStatusState extends NyState { Align( child: LinkButton( title: trans("Back to Home"), - action: () => - Navigator.pushReplacementNamed(context, "/home"), + action: () { + routeToInitial(); + }, ), alignment: Alignment.bottomCenter, ), diff --git a/LabelStoreMax/lib/resources/pages/coupon_page.dart b/LabelStoreMax/lib/resources/pages/coupon_page.dart index 3698faf..31b4c19 100644 --- a/LabelStoreMax/lib/resources/pages/coupon_page.dart +++ b/LabelStoreMax/lib/resources/pages/coupon_page.dart @@ -13,7 +13,6 @@ import '/app/models/cart.dart'; import '/app/models/cart_line_item.dart'; import '/app/models/checkout_session.dart'; import '/bootstrap/helpers.dart'; -import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -25,9 +24,8 @@ class CouponPage extends StatefulWidget { createState() => _CouponPageState(); } -class _CouponPageState extends State { +class _CouponPageState extends NyState { List _coupons = []; - bool _isLoading = false; final couponController = TextEditingController(); @@ -45,28 +43,16 @@ class _CouponPageState extends State { _showAlert(message: trans("Added to checkout")); CheckoutSession.getInstance.coupon = coupon; - Navigator.of(context).pop(); + pop(result: coupon); } Future findCoupon(String couponCode) async { - setState(() { - _isLoading = true; - }); - _coupons = await (appWooSignal( (api) => api.getCoupons(code: couponCode, perPage: 100), )); - - setState(() { - _isLoading = false; - }); } final _formKey = GlobalKey(); - @override - void initState() { - super.initState(); - } @override Widget build(BuildContext context) { @@ -120,14 +106,16 @@ class _CouponPageState extends State { SizedBox( height: 25, ), - (_isLoading == true) - ? AppLoaderWidget() - : PrimaryButton( - action: () => _applyCoupon(checkoutSession), - title: trans('Apply'), - ), + PrimaryButton( + isLoading: isLocked('find_coupon'), + action: () => _applyCoupon(checkoutSession), + title: trans('Apply'), + ), LinkButton( - title: trans("Cancel"), action: () => Navigator.pop(context)), + title: trans("Cancel"), + action: () { + pop(); + }), ], ), ), @@ -135,7 +123,9 @@ class _CouponPageState extends State { } _applyCoupon(CheckoutSession checkoutSession) async { - await findCoupon(couponController.text); + await lockRelease('find_coupon', perform: () async { + await findCoupon(couponController.text); + }); if (_formKey.currentState!.validate()) { // No coupons found diff --git a/LabelStoreMax/lib/resources/pages/home_page.dart b/LabelStoreMax/lib/resources/pages/home_page.dart index 5ebdb6e..f4355f2 100644 --- a/LabelStoreMax/lib/resources/pages/home_page.dart +++ b/LabelStoreMax/lib/resources/pages/home_page.dart @@ -10,9 +10,12 @@ import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_app/resources/pages/account_order_detail_page.dart'; -import 'package:flutter_app/resources/pages/product_detail_page.dart'; +import '/resources/pages/account_order_detail_page.dart'; import 'package:nylo_framework/nylo_framework.dart'; +import '/app/events/firebase_on_message_order_event.dart'; +import '/app/events/order_notification_event.dart'; +import '/app/events/product_notification_event.dart'; +import '/bootstrap/helpers.dart'; import '/bootstrap/app_helper.dart'; import '/resources/widgets/compo_theme_widget.dart'; import '/resources/widgets/mello_theme_widget.dart'; @@ -20,7 +23,6 @@ import '/resources/widgets/notic_theme_widget.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; class HomePage extends StatefulWidget { - static String path = "/home"; HomePage(); @@ -31,7 +33,6 @@ class HomePage extends StatefulWidget { class _HomePageState extends NyState { _HomePageState(); - final GlobalKey _key = GlobalKey(); final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig; @override @@ -40,7 +41,8 @@ class _HomePageState extends NyState { } _enableFcmNotifications() async { - bool? firebaseFcmIsEnabled = AppHelper.instance.appConfig?.firebaseFcmIsEnabled; + bool? firebaseFcmIsEnabled = + AppHelper.instance.appConfig?.firebaseFcmIsEnabled; firebaseFcmIsEnabled ??= getEnv('FCM_ENABLED', defaultValue: false); if (firebaseFcmIsEnabled != true) return; @@ -48,25 +50,70 @@ class _HomePageState extends NyState { FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { /// WP Notify - Product notification if (message.data.containsKey('product_id')) { - routeTo(ProductDetailPage.path, data: int.parse(message.data['product_id'])); + event(data: {"RemoteMessage": message}); } + + /// WP Notify - Order notification + if (message.data.containsKey('order_id')) { + event(data: {"RemoteMessage": message}); + } + }); + + FirebaseMessaging.onMessage.listen((RemoteMessage message) { /// WP Notify - Order notification if (message.data.containsKey('order_id')) { - routeTo(AccountOrderDetailPage.path, data: int.parse(message.data['order_id'])); + event(data: {"RemoteMessage": message}); + _maybeShowSnackBar(message); } }); } + /// Attempt to show a snackbar if the user is on the same page + _maybeShowSnackBar(RemoteMessage message) async { + if (!(await canSeeRemoteMessage(message))) { + return; + } + _showSnackBar(message.notification?.body, onPressed: () { + routeTo(AccountOrderDetailPage.path, + data: int.parse(message.data['order_id'])); + }); + } + + _showSnackBar(String? message, {Function()? onPressed}) { + SnackBar snackBar = SnackBar( + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${'New notification received'.tr()} 🚨', + style: TextStyle(fontWeight: FontWeight.w600), + ), + if (message != null) Text(message) + ], + ), + action: onPressed == null + ? null + : SnackBarAction( + label: 'View'.tr(), + onPressed: onPressed, + ), + duration: Duration(milliseconds: 4500), + ); + + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + @override Widget build(BuildContext context) { - Widget theme = - MelloThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp); - if (AppHelper.instance.appConfig!.theme == "notic") { - theme = NoticThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp); - } - if (AppHelper.instance.appConfig!.theme == "compo") { - theme = CompoThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp); - } - return theme; + return match( + AppHelper.instance.appConfig?.theme, + () => { + "notic": NoticThemeWidget(wooSignalApp: _wooSignalApp), + "compo": CompoThemeWidget(wooSignalApp: _wooSignalApp), + "mello": MelloThemeWidget(wooSignalApp: _wooSignalApp), + }, + defaultValue: MelloThemeWidget(wooSignalApp: _wooSignalApp)); } } diff --git a/LabelStoreMax/lib/resources/pages/home_search_page.dart b/LabelStoreMax/lib/resources/pages/home_search_page.dart index 6b704fb..182e57b 100644 --- a/LabelStoreMax/lib/resources/pages/home_search_page.dart +++ b/LabelStoreMax/lib/resources/pages/home_search_page.dart @@ -9,13 +9,13 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; +import '/resources/pages/browse_search_page.dart'; import '/bootstrap/app_helper.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import '../widgets/woosignal_ui.dart'; - class HomeSearchPage extends StatefulWidget { static String path = "/home-search"; HomeSearchPage(); @@ -29,15 +29,9 @@ class _HomeSearchPageState extends State { final TextEditingController _txtSearchController = TextEditingController(); - @override - void initState() { - super.initState(); - } - _actionSearch() { - Navigator.pushNamed(context, "/product-search", - arguments: _txtSearchController.text) - .then((search) { + routeTo(BrowseSearchPage.path, data: _txtSearchController.text, + onPop: (value) { if (["notic", "compo"].contains(AppHelper.instance.appConfig!.theme) == false) { Navigator.pop(context); diff --git a/LabelStoreMax/lib/resources/pages/leave_review_page.dart b/LabelStoreMax/lib/resources/pages/leave_review_page.dart index 528c56d..cb04709 100644 --- a/LabelStoreMax/lib/resources/pages/leave_review_page.dart +++ b/LabelStoreMax/lib/resources/pages/leave_review_page.dart @@ -10,7 +10,6 @@ import 'package:flutter/material.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/safearea_widget.dart'; @@ -21,14 +20,10 @@ import 'package:woosignal/models/response/product_review.dart'; import 'package:wp_json_api/models/responses/wc_customer_info_response.dart' as wc_customer_info; import 'package:wp_json_api/wp_json_api.dart'; -import '../../app/controllers/leave_review_controller.dart'; class LeaveReviewPage extends NyStatefulWidget { static String path = "/product-leave-review"; - @override - final LeaveReviewController controller = LeaveReviewController(); - LeaveReviewPage({Key? key}) : super(path, key: key, child: _LeaveReviewPageState()); } @@ -49,7 +44,6 @@ class _LeaveReviewPageState extends NyState { _rating = 5; } - @override Widget build(BuildContext context) { return Scaffold( @@ -170,12 +164,10 @@ class _LeaveReviewPageState extends NyState { } Future _fetchWpUserData() async { - String? userToken = await readAuthToken(); - wc_customer_info.WCCustomerInfoResponse? wcCustomerInfoResponse; try { - wcCustomerInfoResponse = await WPJsonAPI.instance - .api((request) => request.wcCustomerInfo(userToken!)); + wcCustomerInfoResponse = + await WPJsonAPI.instance.api((request) => request.wcCustomerInfo()); if (wcCustomerInfoResponse == null) { return null; diff --git a/LabelStoreMax/lib/resources/pages/no_connection_page.dart b/LabelStoreMax/lib/resources/pages/no_connection_page.dart index 77b58cc..7c80280 100644 --- a/LabelStoreMax/lib/resources/pages/no_connection_page.dart +++ b/LabelStoreMax/lib/resources/pages/no_connection_page.dart @@ -75,6 +75,6 @@ class _NoConnectionPageState extends State { } AppHelper.instance.appConfig = wooSignalApp; - Navigator.pushNamed(context, "/home"); + routeToInitial(); } } diff --git a/LabelStoreMax/lib/resources/pages/notifications_page.dart b/LabelStoreMax/lib/resources/pages/notifications_page.dart new file mode 100644 index 0000000..5868ca1 --- /dev/null +++ b/LabelStoreMax/lib/resources/pages/notifications_page.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import '/bootstrap/helpers.dart'; +import '/resources/pages/account_order_detail_page.dart'; +import '/resources/widgets/notification_icon_widget.dart'; +import 'package:nylo_framework/nylo_framework.dart'; +import 'package:wp_json_api/models/wp_user.dart'; +import 'package:wp_json_api/wp_json_api.dart'; + +class NotificationsPage extends NyStatefulWidget { + static const path = '/notifications'; + + NotificationsPage() : super(path, child: _NotificationsPageState()); +} + +class _NotificationsPageState extends NyState { + WpUser? _wpUser; + + @override + boot() async { + _wpUser = (await WPJsonAPI.wpUser()); + } + + @override + Widget view(BuildContext context) { + return PopScope( + onPopInvoked: (didPop) async { + await NyNotification.markReadAll(); + updateState(NotificationIcon.state); + }, + child: Scaffold( + appBar: AppBar( + title: Text("Notifications".tr()), + actions: [ + TextButton( + onPressed: () async { + await NyNotification.markReadAll(); + showStatusAlert( + context, + title: trans("Success"), + subtitle: trans("All notifications marked as read"), + duration: 1, + icon: Icons.notifications, + ); + setState(() {}); + }, + child: Text( + "Mark all read".tr(), + ), + ), + ], + ), + body: SafeArea( + child: Column( + children: [ + Container( + width: double.infinity, + margin: EdgeInsets.only(left: 18, right: 18, bottom: 18), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8)), + child: Text( + "Showing last 30 days".tr(), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Colors.grey.shade800), + ), + ), + Expanded( + child: NyNotification.renderListNotificationsWithSeparator( + (notificationItem) { + if (notificationItem.meta != null && + notificationItem.meta!.containsKey('user_id')) { + String? userId = notificationItem.meta?['user_id']; + + if (userId != _wpUser?.id.toString()) { + return SizedBox.shrink(); + } + } + String? createdAt = notificationItem.createdAt; + if (createdAt != null) { + DateTime createdAtDate = DateTime.parse(createdAt); + createdAt = createdAtDate.toTimeAgoString(); + } + return ListTile( + contentPadding: + EdgeInsets.symmetric(horizontal: 16.0, vertical: 4), + title: Text( + notificationItem.title ?? "", + style: TextStyle( + fontWeight: notificationItem.hasRead == true + ? null + : FontWeight.w800), + ), + leading: Container( + child: Icon(Icons.shopping_bag_outlined), + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(8), + ), + ), + subtitle: NyRichText( + style: TextStyle(color: Colors.black), + children: [ + Text( + notificationItem.message ?? "", + style: TextStyle( + fontWeight: notificationItem.hasRead == true + ? null + : FontWeight.w800), + ), + if (createdAt != null) + Text("\n$createdAt", + style: TextStyle(color: Colors.grey.shade600)) + ], + ), + trailing: Text("View".tr()), + onTap: () { + dynamic orderId = notificationItem.meta?['order_id']; + routeTo(AccountOrderDetailPage.path, + data: int.parse(orderId.toString())); + }, + ); + }, loading: SizedBox.shrink()), + ), + ], + )), + ), + ); + } +} diff --git a/LabelStoreMax/lib/resources/pages/product_detail_page.dart b/LabelStoreMax/lib/resources/pages/product_detail_page.dart index b7b07a4..47599dc 100644 --- a/LabelStoreMax/lib/resources/pages/product_detail_page.dart +++ b/LabelStoreMax/lib/resources/pages/product_detail_page.dart @@ -9,6 +9,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; import '/app/controllers/product_detail_controller.dart'; import '/app/models/cart_line_item.dart'; import '/bootstrap/app_helper.dart'; @@ -25,12 +26,9 @@ import 'package:woosignal/models/response/product_variation.dart' import 'package:woosignal/models/response/product.dart' as ws_product; import 'package:woosignal/models/response/woosignal_app.dart'; -class ProductDetailPage extends NyStatefulWidget { +class ProductDetailPage extends NyStatefulWidget { static String path = "/product-detail"; - @override - final ProductDetailController controller = ProductDetailController(); - ProductDetailPage({Key? key}) : super(path, key: key, child: _ProductDetailState()); } @@ -42,7 +40,6 @@ class _ProductDetailState extends NyState { final Map _tmpAttributeObj = {}; final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig; - @override boot() async { _product = widget.controller.data(); diff --git a/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart b/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart index edb1bcc..809460c 100644 --- a/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart +++ b/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart @@ -9,7 +9,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/app/controllers/product_image_viewer_controller.dart'; import '/resources/widgets/cached_image_widget.dart'; import '/resources/widgets/safearea_widget.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart'; @@ -18,10 +17,6 @@ import 'package:nylo_framework/nylo_framework.dart'; class ProductImageViewerPage extends NyStatefulWidget { static String path = "/product-images"; - @override - final ProductImageViewerController controller = - ProductImageViewerController(); - ProductImageViewerPage({Key? key}) : super(path, key: key, child: _ProductImageViewerPageState()); } diff --git a/LabelStoreMax/lib/resources/pages/product_reviews_page.dart b/LabelStoreMax/lib/resources/pages/product_reviews_page.dart index 4b5bfda..4bca33b 100644 --- a/LabelStoreMax/lib/resources/pages/product_reviews_page.dart +++ b/LabelStoreMax/lib/resources/pages/product_reviews_page.dart @@ -8,209 +8,117 @@ // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -import 'package:collection/collection.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '/app/controllers/product_reviews_loader_controller.dart'; -import '/resources/widgets/app_loader_widget.dart'; +import '/bootstrap/helpers.dart'; import '/resources/widgets/no_results_for_products_widget.dart'; import '/resources/widgets/product_review_item_container_widget.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; -import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; -import 'package:woosignal/models/response/product_review.dart'; import 'package:woosignal/models/response/product.dart'; -import '../../app/controllers/product_reviews_controller.dart'; +import 'package:woosignal/models/response/product_review.dart'; class ProductReviewsPage extends NyStatefulWidget { static String path = "/product-reviews"; - @override - final ProductReviewsController controller = ProductReviewsController(); - ProductReviewsPage({Key? key}) : super(path, key: key, child: _ProductReviewsPageState()); } class _ProductReviewsPageState extends NyState { - final RefreshController _refreshController = - RefreshController(initialRefresh: false); Product? _product; - bool _shouldStopRequests = false, _isLoading = true; - final ProductReviewsLoaderController _productReviewsLoaderController = - ProductReviewsLoaderController(); @override - init() async { + boot() async { _product = widget.data() as Product?; - await fetchProductReviews(); } - @override - Widget build(BuildContext context) { - List productReviews = - _productReviewsLoaderController.getResults(); + Widget view(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(trans('Reviews')), centerTitle: true, ), - body: _isLoading - ? AppLoaderWidget() - : SafeArea( + body: SafeArea( + child: Column( + children: [ + Container( + height: mediaQuery.size.height / 5, + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + margin: EdgeInsets.symmetric(vertical: 16), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.black12))), child: Column( - // shrinkWrap: true, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - height: mediaQuery.size.height / 5, - padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), - margin: EdgeInsets.symmetric(vertical: 16), - decoration: BoxDecoration( - border: - Border(bottom: BorderSide(color: Colors.black12))), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - child: Text( - _product!.name!, - style: Theme.of(context).textTheme.titleLarge, - ), - ), - Container( - padding: EdgeInsets.symmetric(vertical: 8), - child: Text( - "${_product!.ratingCount} Reviews", - style: Theme.of(context).textTheme.bodyMedium, - ), - ), - Row( - children: [ - Container( - margin: EdgeInsets.only(right: 8), - child: Text( - "${_product!.averageRating!} Stars", - style: Theme.of(context).textTheme.bodyMedium, - ), - ), - RatingBarIndicator( - rating: double.parse(_product!.averageRating!), - itemBuilder: (context, index) => Icon( - Icons.star, - color: Colors.amber, - ), - itemCount: 5, - itemSize: 20.0, - direction: Axis.horizontal, - ), - ], - ), - ], + child: Text( + _product!.name!, + style: Theme.of(context).textTheme.titleLarge, ), ), - Expanded( - child: SmartRefresher( - enablePullDown: true, - enablePullUp: true, - footer: CustomFooter( - builder: (BuildContext context, LoadStatus? mode) { - Widget body; - if (mode == LoadStatus.idle) { - body = Text(trans("pull up load")); - } else if (mode == LoadStatus.loading) { - body = CupertinoActivityIndicator(); - } else if (mode == LoadStatus.failed) { - body = Text(trans("Load Failed! Click retry!")); - } else if (mode == LoadStatus.canLoading) { - body = Text(trans("release to load more")); - } else { - return SizedBox.shrink(); - } - return Container( - height: 55.0, - child: Center(child: body), - ); - }, - ), - controller: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - child: (productReviews.isNotEmpty - ? StaggeredGrid.count( - crossAxisCount: 2, - axisDirection: AxisDirection.down, - children: - productReviews.mapIndexed((index, value) { - ProductReview productReview = - productReviews[index]; - - return StaggeredGridTile.fit( - crossAxisCellCount: 2, - // mainAxisCellCount: 2, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 16, vertical: 8), - margin: EdgeInsets.only(bottom: 8), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.black12))), - child: ProductReviewItemContainerWidget( - productReview: productReview), - )); - }).toList(), - mainAxisSpacing: 4.0, - crossAxisSpacing: 4.0, - ) - : NoResultsForProductsWidget()), + Container( + padding: EdgeInsets.symmetric(vertical: 8), + child: Text( + "${_product!.ratingCount} Reviews", + style: Theme.of(context).textTheme.bodyMedium, ), - ) + ), + Row( + children: [ + Container( + margin: EdgeInsets.only(right: 8), + child: Text( + "${_product!.averageRating!} Stars", + style: Theme.of(context).textTheme.bodyMedium, + ), + ), + RatingBarIndicator( + rating: double.parse(_product!.averageRating!), + itemBuilder: (context, index) => Icon( + Icons.star, + color: Colors.amber, + ), + itemCount: 5, + itemSize: 20.0, + direction: Axis.horizontal, + ), + ], + ), ], ), ), + Expanded( + child: NyPullToRefresh( + data: (page) async { + if (_product == null) { + return null; + } + return appWooSignal((api) => api.getProductReviews( + product: [_product!.id!], + perPage: 50, + page: page, + status: "approved", + )); + }, + child: (context, review) { + review as ProductReview; + return Container( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + margin: EdgeInsets.only(bottom: 8), + decoration: BoxDecoration( + border: + Border(bottom: BorderSide(color: Colors.black12))), + child: + ProductReviewItemContainerWidget(productReview: review), + ); + }, + empty: NoResultsForProductsWidget(), + )) + ], + ), + ), ); } - - _onRefresh() async { - _productReviewsLoaderController.clear(); - await fetchProductReviews(); - - setState(() { - _shouldStopRequests = false; - _refreshController.refreshCompleted(resetFooterState: true); - }); - } - - _onLoading() async { - await fetchProductReviews(); - - if (mounted) { - setState(() {}); - if (_shouldStopRequests) { - _refreshController.loadNoData(); - } else { - _refreshController.loadComplete(); - } - } - } - - Future fetchProductReviews() async { - await _productReviewsLoaderController.loadProductReviews( - product: _product, - hasResults: (result) { - if (result == false) { - setState(() { - _shouldStopRequests = true; - }); - return false; - } - return true; - }, - didFinish: () => setState(() { - _isLoading = false; - })); - } } diff --git a/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart b/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart index 1a3cd6a..bd61996 100644 --- a/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart +++ b/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart @@ -9,13 +9,13 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/product_detail_page.dart'; import '/bootstrap/helpers.dart'; import '/resources/widgets/cached_image_widget.dart'; import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/product.dart'; class WishListPageWidget extends StatefulWidget { - static String path = "/wishlist"; @override @@ -81,9 +81,8 @@ class _WishListPageWidgetState extends NyState { itemBuilder: (BuildContext context, int index) { Product product = _products[index]; return InkWell( - onTap: () => Navigator.pushNamed( - context, "/product-detail", - arguments: product), + onTap: () => + routeTo(ProductDetailPage.path, data: product), child: Container( child: Row( children: [ diff --git a/LabelStoreMax/lib/resources/themes/dark_theme.dart b/LabelStoreMax/lib/resources/themes/dark_theme.dart index eb92e5b..d0f64f1 100644 --- a/LabelStoreMax/lib/resources/themes/dark_theme.dart +++ b/LabelStoreMax/lib/resources/themes/dark_theme.dart @@ -63,7 +63,8 @@ ThemeData darkTheme(ColorStyles darkColors) { selectedItemColor: darkColors.bottomTabBarLabelSelected, ), textTheme: darkTheme, - colorScheme: ColorScheme.dark(background: darkColors.background), + colorScheme: ColorScheme.dark( + background: darkColors.background, primary: darkColors.primaryContent), ); } diff --git a/LabelStoreMax/lib/resources/themes/light_theme.dart b/LabelStoreMax/lib/resources/themes/light_theme.dart index 624e635..5fbf712 100644 --- a/LabelStoreMax/lib/resources/themes/light_theme.dart +++ b/LabelStoreMax/lib/resources/themes/light_theme.dart @@ -66,8 +66,9 @@ ThemeData lightTheme(ColorStyles lightColors) { selectedItemColor: lightColors.bottomTabBarLabelSelected, ), textTheme: lightTheme, - colorScheme: - ColorScheme.light(background: lightColors.background), + colorScheme: ColorScheme.light( + background: lightColors.background, + primary: lightColors.primaryContent), ); } diff --git a/LabelStoreMax/lib/resources/widgets/account_detail_orders_widget.dart b/LabelStoreMax/lib/resources/widgets/account_detail_orders_widget.dart index 6a8beb5..b73f337 100644 --- a/LabelStoreMax/lib/resources/widgets/account_detail_orders_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/account_detail_orders_widget.dart @@ -8,91 +8,32 @@ // 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/material.dart'; -import '/app/controllers/customer_orders_loader_controller.dart'; +import '/resources/pages/account_order_detail_page.dart'; +import 'package:wp_json_api/models/wp_user.dart'; +import 'package:wp_json_api/wp_json_api.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; -import '/resources/widgets/app_loader_widget.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:woosignal/models/response/order.dart'; class AccountDetailOrdersWidget extends StatefulWidget { @override - createState() => - _AccountDetailOrdersWidgetState(); + createState() => _AccountDetailOrdersWidgetState(); } -class _AccountDetailOrdersWidgetState extends State { - bool _isLoadingOrders = true, _shouldStopRequests = false; - final RefreshController _refreshController = - RefreshController(initialRefresh: false); - final CustomerOrdersLoaderController _customerOrdersLoaderController = - CustomerOrdersLoaderController(); - +class _AccountDetailOrdersWidgetState + extends NyState { @override - void initState() { - super.initState(); - fetchOrders(); - } + bool get showInitialLoader => false; @override - Widget build(BuildContext context) { - List orders = _customerOrdersLoaderController.getResults(); - - if (_isLoadingOrders == true) { - return AppLoaderWidget(); - } + void boot() {} - if (orders.isEmpty) { - return Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.shopping_cart, - color: Colors.black54, - size: 40, - ), - Text( - trans("No orders found"), - ), - ], - ), - ); - } - - return SmartRefresher( - enablePullDown: true, - enablePullUp: true, - footer: CustomFooter( - builder: (BuildContext context, LoadStatus? mode) { - Widget body; - if (mode == LoadStatus.idle) { - body = Text(trans("pull up load")); - } else if (mode == LoadStatus.loading) { - body = CupertinoActivityIndicator(); - } else if (mode == LoadStatus.failed) { - body = Text(trans("Load Failed! Click retry!")); - } else if (mode == LoadStatus.canLoading) { - body = Text(trans("release to load more")); - } else { - body = Text(trans("No more orders")); - } - return Container( - height: 55.0, - child: Center(child: body), - ); - }, - ), - controller: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - child: ListView.builder( - itemBuilder: (context, i) { - Order order = orders[i]; + @override + Widget view(BuildContext context) { + return NyPullToRefresh( + child: (context, order) { + order as Order; return Card( child: ListTile( contentPadding: EdgeInsets.only( @@ -157,12 +98,12 @@ class _AccountDetailOrdersWidgetState extends State { ), Text( "${dateFormatted( - date: order.dateCreated!, - formatType: formatForDateTime(FormatType.date), - )}\n${dateFormatted( - date: order.dateCreated!, - formatType: formatForDateTime(FormatType.time), - )}", + date: order.dateCreated!, + formatType: formatForDateTime(FormatType.date), + )}\n${dateFormatted( + date: order.dateCreated!, + formatType: formatForDateTime(FormatType.time), + )}", textAlign: TextAlign.right, style: Theme.of(context).textTheme.bodyLarge!.copyWith( fontWeight: FontWeight.w400, @@ -177,66 +118,123 @@ class _AccountDetailOrdersWidgetState extends State { Icon(Icons.chevron_right), ], ), - onTap: () => _viewOrderDetail(i, order.id), + onTap: () => _viewOrderDetail(order.id), ), ); }, - itemCount: orders.length, - ), - ); - } - - void _onRefresh() async { - _customerOrdersLoaderController.clear(); - await fetchOrders(); - - setState(() { - _shouldStopRequests = false; - _refreshController.refreshCompleted(resetFooterState: true); - }); - } - - void _onLoading() async { - await fetchOrders(); - - if (mounted) { - setState(() {}); - if (_shouldStopRequests) { - _refreshController.loadNoData(); - } else { - _refreshController.loadComplete(); - } - } - } - - fetchOrders() async { - String? userId = await readUserId(); - if (userId == null) { - setState(() { - _isLoadingOrders = false; - }); - return; - } - await _customerOrdersLoaderController.loadOrders( - hasResults: (result) { - if (result == false) { - setState(() { - _isLoadingOrders = false; - _shouldStopRequests = true; - }); - return false; - } - return true; + data: (page) async { + WpUser? wpUser = await WPJsonAPI.wpUser(); + return await appWooSignal((api) => + api.getOrders(customer: wpUser?.id, page: page, perPage: 50)); }, - didFinish: () => setState(() { - _isLoadingOrders = false; - }), - userId: userId); + empty: Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.shopping_cart, + color: Colors.black54, + size: 40, + ), + Text( + trans("No orders found"), + ), + ], + ), + ), + loading: Container( + height: 200, + width: double.infinity, + child: ListView( + children: [ + Card( + child: ListTile( + contentPadding: EdgeInsets.only( + top: 5, + bottom: 5, + left: 8, + right: 6, + ), + title: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Color(0xFFFCFCFC), + width: 1, + ), + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Some Text", + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + "Some Text", + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + subtitle: Padding( + padding: const EdgeInsets.only(top: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + formatStringCurrency(total: "Some Text"), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(fontWeight: FontWeight.w600), + textAlign: TextAlign.left, + ), + Text( + "Some Text", + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith(fontWeight: FontWeight.w600), + textAlign: TextAlign.left, + ), + ], + ), + Text( + "Some Text", + textAlign: TextAlign.right, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + trailing: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.chevron_right), + ], + ), + ), + ) + ], + ), + ), + useSkeletonizer: true); } - _viewOrderDetail(int i, int? orderId) => Navigator.pushNamed( - context, - "/account-order-detail", - arguments: orderId, - ); + _viewOrderDetail(int? orderId) { + routeTo(AccountOrderDetailPage.path, data: orderId); + } } diff --git a/LabelStoreMax/lib/resources/widgets/account_detail_settings_widget.dart b/LabelStoreMax/lib/resources/widgets/account_detail_settings_widget.dart index 53c1a89..fd87f1d 100644 --- a/LabelStoreMax/lib/resources/widgets/account_detail_settings_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/account_detail_settings_widget.dart @@ -9,46 +9,59 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; +import '/resources/pages/account_detail_page.dart'; +import '/resources/pages/account_delete_page.dart'; +import '/resources/pages/account_profile_update_page.dart'; +import '/resources/pages/account_shipping_details_page.dart'; +import '/app/events/logout_event.dart'; import 'package:nylo_framework/nylo_framework.dart'; -class AccountDetailSettingsWidget extends StatelessWidget { - const AccountDetailSettingsWidget({super.key, required this.refreshAccount}); - final Function refreshAccount; +class AccountDetailSettingsWidget extends StatefulWidget { + const AccountDetailSettingsWidget({super.key}); + + @override + State createState() => + _AccountDetailSettingsWidgetState(); +} + +class _AccountDetailSettingsWidgetState + extends NyState { @override Widget build(BuildContext context) { return ListView( children: [ Card( child: ListTile( - leading: Icon(Icons.account_circle), - title: Text(trans("Update details")), - onTap: () => - Navigator.pushNamed(context, "/account-update").then((onValue) { - refreshAccount(); - }), - ), + leading: Icon(Icons.account_circle), + title: Text(trans("Update details")), + onTap: () => + routeTo(AccountProfileUpdatePage.path, onPop: (value) { + StateAction.refreshPage(AccountDetailPage.path); + })), ), Card( child: ListTile( leading: Icon(Icons.local_shipping), title: Text(trans("Billing/shipping details")), - onTap: () => - Navigator.pushNamed(context, "/account-shipping-details"), + onTap: () => routeTo(AccountShippingDetailsPage.path), ), ), Card( child: ListTile( leading: Icon(Icons.no_accounts_rounded), title: Text(trans("Delete Account")), - onTap: () => Navigator.pushNamed(context, "/account-delete"), + onTap: () => routeTo(AccountDeletePage.path), ), ), Card( child: ListTile( leading: Icon(Icons.exit_to_app), title: Text(trans("Logout")), - onTap: () => authLogout(context), + onTap: () { + confirmAction(() { + event(); + }, title: "Are you sure?".tr()); + }, ), ), ], diff --git a/LabelStoreMax/lib/resources/widgets/buttons.dart b/LabelStoreMax/lib/resources/widgets/buttons.dart index 7093c3c..2497a8d 100644 --- a/LabelStoreMax/lib/resources/widgets/buttons.dart +++ b/LabelStoreMax/lib/resources/widgets/buttons.dart @@ -58,14 +58,11 @@ class SecondaryButton extends StatelessWidget { } class LinkButton extends StatelessWidget { - const LinkButton({ - super.key, - this.title, - this.action, - }); + const LinkButton({super.key, this.title, this.action, this.selected}); final String? title; final Function? action; + final bool? selected; @override Widget build(BuildContext context) { @@ -82,7 +79,11 @@ class LinkButton extends StatelessWidget { child: Text( title!, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.bodyLarge, + style: selected == true + ? Theme.of(context).textTheme.bodyLarge!.copyWith( + fontWeight: FontWeight.bold, + ) + : Theme.of(context).textTheme.bodyLarge, )), ), onTap: action == null ? null : () async => await action!(), diff --git a/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart b/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart index f52b207..705df5e 100644 --- a/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart @@ -9,6 +9,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/cart_page.dart'; +import 'package:nylo_framework/nylo_framework.dart'; import '/resources/widgets/cart_quantity_widget.dart'; class CartIconWidget extends StatefulWidget { @@ -42,8 +44,7 @@ class _CartIconWidgetState extends State { ) ], ), - onPressed: () => Navigator.pushNamed(context, "/cart") - .then((value) => setState(() {})), + onPressed: () => routeTo(CartPage.path), ), ); } diff --git a/LabelStoreMax/lib/resources/widgets/cart_item_container_widget.dart b/LabelStoreMax/lib/resources/widgets/cart_item_container_widget.dart new file mode 100644 index 0000000..08566fa --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/cart_item_container_widget.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/app/models/cart_line_item.dart'; +import 'package:flutter_app/bootstrap/helpers.dart'; +import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class CartItemContainer extends StatelessWidget { + const CartItemContainer({ + super.key, + required this.cartLineItem, + required this.actionIncrementQuantity, + required this.actionDecrementQuantity, + required this.actionRemoveItem, + }); + + final CartLineItem cartLineItem; + final void Function() actionIncrementQuantity; + final void Function() actionDecrementQuantity; + final void Function() actionRemoveItem; + + @override + Widget build(BuildContext context) => Container( + margin: EdgeInsets.only(bottom: 7), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Colors.black12, + width: 1, + ), + ), + ), + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: CachedImageWidget( + image: (cartLineItem.imageSrc == "" + ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") + : cartLineItem.imageSrc), + width: 100, + height: 100, + fit: BoxFit.contain, + ), + flex: 2, + ), + Flexible( + child: Padding( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + cartLineItem.name!, + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(fontWeight: FontWeight.bold), + overflow: TextOverflow.ellipsis, + maxLines: 3, + ), + if (cartLineItem.variationOptions != null) + Text(cartLineItem.variationOptions!, + style: Theme.of(context).textTheme.bodyLarge), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + (cartLineItem.stockStatus == "outofstock" + ? trans("Out of stock") + : trans("In Stock")), + style: (cartLineItem.stockStatus == "outofstock" + ? Theme.of(context).textTheme.bodySmall + : Theme.of(context).textTheme.bodyMedium), + ), + Text( + formatDoubleCurrency( + total: parseWcPrice(cartLineItem.total), + ), + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ) + ], + ), + ], + ), + padding: EdgeInsets.only(left: 8), + ), + flex: 5, + ) + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon(Icons.remove_circle_outline), + onPressed: actionDecrementQuantity, + highlightColor: Colors.transparent, + ), + Text(cartLineItem.quantity.toString(), + style: Theme.of(context).textTheme.titleLarge), + IconButton( + icon: Icon(Icons.add_circle_outline), + onPressed: actionIncrementQuantity, + highlightColor: Colors.transparent, + ), + ], + ), + IconButton( + alignment: Alignment.centerRight, + icon: Icon(Icons.delete_outline, + color: Colors.deepOrangeAccent, size: 20), + onPressed: actionRemoveItem, + highlightColor: Colors.transparent, + ), + ], + ) + ], + ), + ); +} diff --git a/LabelStoreMax/lib/resources/widgets/cart_quantity_widget.dart b/LabelStoreMax/lib/resources/widgets/cart_quantity_widget.dart index 038f66a..510e478 100644 --- a/LabelStoreMax/lib/resources/widgets/cart_quantity_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/cart_quantity_widget.dart @@ -4,11 +4,10 @@ import '/app/models/cart_line_item.dart'; import 'package:nylo_framework/nylo_framework.dart'; class CartQuantity extends StatefulWidget { - CartQuantity({super.key, this.childOfNavBar = false}); final bool childOfNavBar; - + static String state = "cart_quantity"; @override @@ -16,7 +15,6 @@ class CartQuantity extends StatefulWidget { } class _CartQuantityState extends NyState { - bool _childOfNavBar = false; _CartQuantityState(childOfNavBar) { @@ -24,10 +22,9 @@ class _CartQuantityState extends NyState { _childOfNavBar = childOfNavBar; } - @override stateUpdated(dynamic data) async { - setState(() { }); + setState(() {}); } @override diff --git a/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart b/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart index 8adec60..0475a8d 100644 --- a/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart @@ -12,8 +12,7 @@ import 'package:flutter/material.dart'; class CategorySubcategoryScrollWidget extends StatefulWidget { @override - createState() => - _CategorySubcategoryScrollWidgetState(); + createState() => _CategorySubcategoryScrollWidgetState(); } class _CategorySubcategoryScrollWidgetState diff --git a/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart index 60f8fbf..092e3d1 100644 --- a/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart @@ -9,6 +9,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/checkout_confirmation_page.dart'; +import '/resources/pages/checkout_payment_type_page.dart'; import '/app/models/checkout_session.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -46,7 +48,8 @@ class CheckoutPaymentTypeWidget extends StatelessWidget { } _actionPayWith() { - Navigator.pushNamed(context, "/checkout-payment-type") - .then((value) => resetState!()); + routeTo(CheckoutPaymentTypePage.path, onPop: (value) { + StateAction.refreshPage(CheckoutConfirmationPage.path, setState: () {}); + }); } } diff --git a/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart index dbbadc5..981af15 100644 --- a/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart @@ -9,23 +9,38 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/checkout_confirmation_page.dart'; +import 'package:woosignal/models/response/coupon.dart'; +import '/resources/pages/coupon_page.dart'; import '/app/models/checkout_session.dart'; import 'package:nylo_framework/nylo_framework.dart'; -class CheckoutSelectCouponWidget extends StatelessWidget { - const CheckoutSelectCouponWidget( - {super.key, - required this.context, - required this.checkoutSession, - required this.resetState}); +class CheckoutSelectCouponWidget extends StatefulWidget { + const CheckoutSelectCouponWidget({ + super.key, + required this.context, + required this.checkoutSession, + }); final CheckoutSession checkoutSession; final BuildContext context; - final Function resetState; + + static String state = "checkout_select_coupon_widget"; + + @override + State createState() => + _CheckoutSelectCouponWidgetState(); +} + +class _CheckoutSelectCouponWidgetState + extends NyState { + _CheckoutSelectCouponWidgetState() { + stateName = CheckoutSelectCouponWidget.state; + } @override Widget build(BuildContext context) { - bool hasCoupon = checkoutSession.coupon != null; + bool hasCoupon = widget.checkoutSession.coupon != null; return Container( height: 50, padding: EdgeInsets.symmetric(vertical: 5), @@ -33,8 +48,14 @@ class CheckoutSelectCouponWidget extends StatelessWidget { onTap: _actionCoupon, child: Row( crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text( + hasCoupon + ? "Coupon Applied: ${widget.checkoutSession.coupon!.code!}" + : trans('Apply Coupon'), + style: Theme.of(context).textTheme.titleSmall, + ), if (hasCoupon == true) IconButton( padding: EdgeInsets.symmetric(vertical: 3), @@ -43,27 +64,24 @@ class CheckoutSelectCouponWidget extends StatelessWidget { Icons.close, size: 19, )), - Text( - hasCoupon - ? "Coupon Applied: ${checkoutSession.coupon!.code!}" - : trans('Apply Coupon'), - style: Theme.of(context).textTheme.titleSmall, - ), + if (hasCoupon == false) + Icon(Icons.arrow_forward_ios, + size: 16, color: Colors.grey.shade600), ], - ), + ).paddingSymmetric(horizontal: 16), ), ); } _clearCoupon() { CheckoutSession.getInstance.coupon = null; - resetState(); + StateAction.refreshPage(CheckoutConfirmationPage.path, setState: () {}); } _actionCoupon() { - if (checkoutSession.billingDetails!.billingAddress == null) { + if (widget.checkoutSession.billingDetails!.billingAddress == null) { showToastNotification( - context, + widget.context, title: trans("Oops"), description: trans("Please select add your billing/shipping address to proceed"), @@ -73,10 +91,11 @@ class CheckoutSelectCouponWidget extends StatelessWidget { return; } - if (checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ?? + if (widget.checkoutSession.billingDetails?.billingAddress + ?.hasMissingFields() ?? true) { showToastNotification( - context, + widget.context, title: trans("Oops"), description: trans("Your billing/shipping details are incomplete"), style: ToastNotificationStyleType.WARNING, @@ -84,7 +103,10 @@ class CheckoutSelectCouponWidget extends StatelessWidget { ); return; } - Navigator.pushNamed(context, "/checkout-coupons") - .then((value) => resetState()); + routeTo(CouponPage.path, onPop: (value) { + if (value is Coupon) { + StateAction.refreshPage(CheckoutConfirmationPage.path, setState: () {}); + } + }); } } diff --git a/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart index ce03c87..b1f4cf1 100644 --- a/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart @@ -9,6 +9,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/checkout_confirmation_page.dart'; +import '/resources/pages/checkout_shipping_type_page.dart'; import '/app/models/checkout_session.dart'; import '/app/models/customer_address.dart'; import '/resources/widgets/woosignal_ui.dart'; @@ -59,7 +61,8 @@ class CheckoutShippingTypeWidget extends StatelessWidget { ); return; } - Navigator.pushNamed(context, "/checkout-shipping-type") - .then((value) => resetState!()); + routeTo(CheckoutShippingTypePage.path, onPop: (value) { + StateAction.refreshPage(CheckoutConfirmationPage.path, setState: () {}); + }); } } diff --git a/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart index 0aa61a8..e0c7a5f 100644 --- a/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart @@ -9,7 +9,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/resources/widgets/woosignal_ui.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; class CheckoutStoreHeadingWidget extends StatelessWidget { const CheckoutStoreHeadingWidget({super.key}); diff --git a/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart index 0692572..6dfc263 100644 --- a/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart @@ -9,6 +9,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/checkout_confirmation_page.dart'; +import '/resources/pages/checkout_details_page.dart'; import '/app/models/checkout_session.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -44,8 +46,8 @@ class CheckoutUserDetailsWidget extends StatelessWidget { } _actionCheckoutDetails() { - Navigator.pushNamed(context, "/checkout-details").then((e) { - resetState!(); + routeTo(CheckoutDetailsPage.path, onPop: (value) { + StateAction.refreshPage(CheckoutConfirmationPage.path, setState: () {}); }); } } diff --git a/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart b/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart index d2a8116..cb1e591 100644 --- a/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart @@ -11,13 +11,17 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; +import '/resources/widgets/notification_icon_widget.dart'; +import '/resources/widgets/product_item_container_widget.dart'; +import '/resources/pages/browse_category_page.dart'; +import '/resources/pages/product_detail_page.dart'; import 'package:woosignal/models/response/product_category_collection.dart'; import '/bootstrap/helpers.dart'; import '/resources/widgets/app_loader_widget.dart'; import '/resources/widgets/buttons.dart'; import '/resources/widgets/cached_image_widget.dart'; import '/resources/widgets/home_drawer_widget.dart'; -import '/resources/widgets/woosignal_ui.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/product_category.dart'; @@ -33,21 +37,31 @@ class CompoHomeWidget extends StatefulWidget { createState() => _CompoHomeWidgetState(); } -class _CompoHomeWidgetState extends State { +class _CompoHomeWidgetState extends NyState { @override - void initState() { - super.initState(); - _loadHome(); + boot() async { + await _loadHome(); } _loadHome() async { if ((widget.wooSignalApp?.productCategoryCollections ?? []).isNotEmpty) { - List productCategoryId = widget.wooSignalApp?.productCategoryCollections.map((e) => int.parse(e.collectionId!)).toList() ?? []; - categories = await (appWooSignal((api) => - api.getProductCategories(parent: 0, perPage: 50, hideEmpty: true, include: productCategoryId))); + List productCategoryId = widget + .wooSignalApp?.productCategoryCollections + .map((e) => int.parse(e.collectionId!)) + .toList() ?? + []; + categories = await (appWooSignal((api) => api.getProductCategories( + parent: 0, + perPage: 50, + hideEmpty: true, + include: productCategoryId))); categories.sort((category1, category2) { - ProductCategoryCollection? productCategoryCollection1 = widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull((element) => element.collectionId == category1.id.toString()); - ProductCategoryCollection? productCategoryCollection2 = widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull((element) => element.collectionId == category2.id.toString()); + ProductCategoryCollection? productCategoryCollection1 = + widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull( + (element) => element.collectionId == category1.id.toString()); + ProductCategoryCollection? productCategoryCollection2 = + widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull( + (element) => element.collectionId == category2.id.toString()); if (productCategoryCollection1 == null) return 0; if (productCategoryCollection2 == null) return 0; @@ -55,7 +69,8 @@ class _CompoHomeWidgetState extends State { if (productCategoryCollection1.position == null) return 0; if (productCategoryCollection2.position == null) return 0; - return productCategoryCollection1.position!.compareTo(productCategoryCollection2.position!); + return productCategoryCollection1.position! + .compareTo(productCategoryCollection2.position!); }); } else { categories = await (appWooSignal((api) => @@ -75,7 +90,6 @@ class _CompoHomeWidgetState extends State { )); if (products.isNotEmpty) { categoryAndProducts.addAll({category: products}); - setState(() {}); } } } @@ -83,20 +97,23 @@ class _CompoHomeWidgetState extends State { List categories = []; Map> categoryAndProducts = {}; - @override - void dispose() { - super.dispose(); - } - @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; - List? bannerImages = widget.wooSignalApp!.bannerImages; + List bannerImages = widget.wooSignalApp?.bannerImages ?? []; return Scaffold( - drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp, productCategories: categories), + drawer: HomeDrawerWidget( + wooSignalApp: widget.wooSignalApp, productCategories: categories), appBar: AppBar( centerTitle: true, title: StoreLogo(), + actions: [ + Flexible( + child: Padding( + padding: const EdgeInsets.only(right: 8.0), + child: NotificationIcon(), + )), + ], elevation: 0, ), body: SafeArea( @@ -105,7 +122,7 @@ class _CompoHomeWidgetState extends State { : ListView( shrinkWrap: true, children: [ - if (bannerImages!.isNotEmpty) + if (bannerImages.isNotEmpty) Container( child: Swiper( itemBuilder: (BuildContext context, int index) { @@ -196,7 +213,8 @@ class _CompoHomeWidgetState extends State { height: MediaQuery.of(cxt).size.height, width: size.width / 2.5, child: ProductItemContainer( - product: product, onTap: _showProduct), + product: product, + onTap: () => _showProduct(product)), ); }, itemCount: catProds.value.length, @@ -212,10 +230,10 @@ class _CompoHomeWidgetState extends State { ); } - _showCategory(ProductCategory productCategory) => - Navigator.pushNamed(context, "/browse-category", - arguments: productCategory); + _showCategory(ProductCategory productCategory) { + routeTo(BrowseCategoryPage.path, data: productCategory); + } _showProduct(Product product) => - Navigator.pushNamed(context, "/product-detail", arguments: product); + routeTo(ProductDetailPage.path, data: product); } diff --git a/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart b/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart index c3f6f33..e2506f0 100644 --- a/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart @@ -1,5 +1,3 @@ -// -// LabelCore // Label StoreMax // // Created by Anthony Gordon. @@ -9,14 +7,13 @@ // 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:wp_json_api/wp_json_api.dart'; import '/app/models/bottom_nav_item.dart'; import '/bootstrap/app_helper.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/pages/account_detail_page.dart'; -import '/resources/pages/account_landing_page.dart'; +import '/resources/pages/account_login_page.dart'; import '/resources/pages/cart_page.dart'; import '/resources/pages/wishlist_page_widget.dart'; import '/resources/pages/home_search_page.dart'; @@ -26,10 +23,8 @@ import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; class CompoThemeWidget extends StatefulWidget { - CompoThemeWidget( - {super.key, required this.globalKey, required this.wooSignalApp}); + CompoThemeWidget({super.key, required this.wooSignalApp}); final WooSignalApp? wooSignalApp; - final GlobalKey globalKey; @override CompoThemeWidgetState createState() => CompoThemeWidgetState(); @@ -123,11 +118,11 @@ class CompoThemeWidgetState extends State { if (AppHelper.instance.appConfig!.wpLoginEnabled == 1) { items.add(BottomNavItem( id: 5, - bottomNavigationBarItem: - BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Account'.tr()), - tabWidget: (await authCheck()) + bottomNavigationBarItem: BottomNavigationBarItem( + icon: Icon(Icons.person), label: 'Account'.tr()), + tabWidget: (await WPJsonAPI.wpUserLoggedIn()) ? AccountDetailPage(showLeadingBackButton: false) - : AccountLandingPage( + : AccountLoginPage( showBackButton: false, ), )); diff --git a/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart b/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart index 87fb8dd..213abb0 100644 --- a/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart @@ -9,14 +9,18 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; +import '/resources/pages/account_detail_page.dart'; +import '/resources/pages/account_login_page.dart'; +import '/resources/pages/cart_page.dart'; +import '/resources/pages/wishlist_page_widget.dart'; +import 'package:wp_json_api/wp_json_api.dart'; import '/resources/pages/browse_category_page.dart'; import 'package:woosignal/models/response/product_category.dart'; import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/widgets/app_version_widget.dart'; import '/resources/widgets/cached_image_widget.dart'; -import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/theme/helper/ny_theme.dart'; import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/menu_link.dart'; @@ -24,7 +28,10 @@ import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:url_launcher/url_launcher.dart'; class HomeDrawerWidget extends StatefulWidget { - const HomeDrawerWidget({super.key, required this.wooSignalApp, this.productCategories = const []}); + const HomeDrawerWidget( + {super.key, + required this.wooSignalApp, + this.productCategories = const []}); final WooSignalApp? wooSignalApp; final List productCategories; @@ -59,37 +66,6 @@ class _HomeDrawerWidgetState extends State { color: ThemeColor.get(context).background, ), ), - if (widget.wooSignalApp?.productCategoryCollections.isNotEmpty ?? false) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - child: Text( - trans("Categories".tr()), - style: Theme.of(context).textTheme.titleSmall!.copyWith( - fontWeight: FontWeight.w600, - ), - textAlign: TextAlign.left, - ), - padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), - ), - ...widget.productCategories.map((collection) { - return ListTile( - title: Text( - collection.name ?? "", - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(fontSize: 16), - ), - trailing: Icon(Icons.keyboard_arrow_right_rounded), - onTap: () { - routeTo(BrowseCategoryPage.path, data: collection); - }, - ); - }) - ]), if (["compo"].contains(_themeType) == false) Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -98,7 +74,9 @@ class _HomeDrawerWidgetState extends State { Padding( child: Text( trans("Menu"), - style: Theme.of(context).textTheme.titleSmall, + style: Theme.of(context).textTheme.titleSmall!.copyWith( + fontWeight: FontWeight.w600, + ), ), padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), ), @@ -139,6 +117,38 @@ class _HomeDrawerWidgetState extends State { ), ], ), + if (widget.wooSignalApp?.productCategoryCollections.isNotEmpty ?? + false) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + child: Text( + trans("Categories".tr()), + style: Theme.of(context).textTheme.titleSmall!.copyWith( + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.left, + ), + padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), + ), + ...widget.productCategories.map((collection) { + return ListTile( + title: Text( + collection.name ?? "", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(fontSize: 16), + ), + trailing: Icon(Icons.keyboard_arrow_right_rounded), + onTap: () { + routeTo(BrowseCategoryPage.path, data: collection); + }, + ); + }) + ]), if (widget.wooSignalApp!.appTermsLink != null && widget.wooSignalApp!.appPrivacyLink != null) Padding( @@ -217,8 +227,14 @@ class _HomeDrawerWidgetState extends State { ), onTap: () async => await launchUrl(Uri.parse(menuLink.linkUrl)), - )) - , + )), + ListTile( + title: Text("Change language".tr()), + leading: Icon(Icons.language), + onTap: () { + NyLanguageSwitcher.showBottomModal(context); + }, + ), ListTile( title: AppVersionWidget(), ), @@ -234,21 +250,24 @@ class _HomeDrawerWidgetState extends State { _actionProfile() async { Navigator.pop(context); - if (widget.wooSignalApp!.wpLoginEnabled == 1 && !(await authCheck())) { - UserAuth.instance.redirect = "/account-detail"; - Navigator.pushNamed(context, "/account-landing"); + if (widget.wooSignalApp!.wpLoginEnabled == 1 && + !(await WPJsonAPI.wpUserLoggedIn())) { + UserAuth.instance.redirect = AccountDetailPage.path; + routeTo(AccountLoginPage.path); return; } - Navigator.pushNamed(context, "/account-detail"); + routeTo(AccountDetailPage.path); } + /// Wishlist action _actionWishlist() async { Navigator.pop(context); - Navigator.pushNamed(context, "/wishlist"); + routeTo(WishListPageWidget.path); } + /// Cart action _actionCart() { Navigator.pop(context); - Navigator.pushNamed(context, "/cart"); + routeTo(CartPage.path); } } diff --git a/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart b/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart index fa51500..011e24c 100644 --- a/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart @@ -10,23 +10,28 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; +import '/resources/widgets/product_item_container_widget.dart'; +import '/resources/pages/browse_category_page.dart'; +import '/resources/pages/home_search_page.dart'; +import '/resources/pages/product_detail_page.dart'; +import '/resources/widgets/cached_image_widget.dart'; +import '/resources/widgets/top_nav_widget.dart'; +import 'package:flutter_swiper_view/flutter_swiper_view.dart'; +import '/resources/widgets/notification_icon_widget.dart'; import 'package:woosignal/models/response/product_category_collection.dart'; -import '/app/controllers/product_loader_controller.dart'; import '/bootstrap/helpers.dart'; import '/resources/widgets/cart_icon_widget.dart'; import '/resources/widgets/home_drawer_widget.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/product_category.dart' as ws_category; import 'package:woosignal/models/response/product.dart' as ws_product; class MelloThemeWidget extends StatefulWidget { - MelloThemeWidget( - {super.key, required this.globalKey, required this.wooSignalApp}); - final GlobalKey globalKey; + MelloThemeWidget({super.key, required this.wooSignalApp}); final WooSignalApp? wooSignalApp; @override @@ -34,38 +39,32 @@ class MelloThemeWidget extends StatefulWidget { } class _MelloThemeWidgetState extends NyState { - final RefreshController _refreshController = - RefreshController(initialRefresh: false); - final ProductLoaderController _productLoaderController = - ProductLoaderController(); - List _categories = []; - bool _shouldStopRequests = false; - - @override - void init() async { - super.init(); - } - @override boot() async { - await _home(); - } - - _home() async { - await fetchProducts(); await _fetchCategories(); } _fetchCategories() async { if ((widget.wooSignalApp?.productCategoryCollections ?? []).isNotEmpty) { - List productCategoryId = widget.wooSignalApp?.productCategoryCollections.map((e) => int.parse(e.collectionId!)).toList() ?? []; - _categories = await (appWooSignal((api) => - api.getProductCategories(parent: 0, perPage: 50, hideEmpty: true, include: productCategoryId))); + List productCategoryId = widget + .wooSignalApp?.productCategoryCollections + .map((e) => int.parse(e.collectionId!)) + .toList() ?? + []; + _categories = await (appWooSignal((api) => api.getProductCategories( + parent: 0, + perPage: 50, + hideEmpty: true, + include: productCategoryId))); _categories.sort((category1, category2) { - ProductCategoryCollection? productCategoryCollection1 = widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull((element) => element.collectionId == category1.id.toString()); - ProductCategoryCollection? productCategoryCollection2 = widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull((element) => element.collectionId == category2.id.toString()); + ProductCategoryCollection? productCategoryCollection1 = + widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull( + (element) => element.collectionId == category1.id.toString()); + ProductCategoryCollection? productCategoryCollection2 = + widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull( + (element) => element.collectionId == category2.id.toString()); if (productCategoryCollection1 == null) return 0; if (productCategoryCollection2 == null) return 0; @@ -73,7 +72,8 @@ class _MelloThemeWidgetState extends NyState { if (productCategoryCollection1.position == null) return 0; if (productCategoryCollection2.position == null) return 0; - return productCategoryCollection1.position!.compareTo(productCategoryCollection2.position!); + return productCategoryCollection1.position! + .compareTo(productCategoryCollection2.position!); }); } else { _categories = await (appWooSignal((api) => @@ -84,7 +84,6 @@ class _MelloThemeWidgetState extends NyState { } _modalBottomSheetMenu() { - widget.globalKey.currentState!.setState(() {}); wsModalBottom( context, title: trans("Categories"), @@ -95,9 +94,7 @@ class _MelloThemeWidgetState extends NyState { title: Text(parseHtmlString(_categories[index].name)), onTap: () { Navigator.pop(context); - Navigator.pushNamed(context, "/browse-category", - arguments: _categories[index]) - .then((value) => setState(() {})); + routeTo(BrowseCategoryPage.path, data: _categories[index]); }, ), ), @@ -108,85 +105,74 @@ class _MelloThemeWidgetState extends NyState { Widget build(BuildContext context) { List? bannerImages = widget.wooSignalApp!.bannerImages; return Scaffold( - drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp, productCategories: _categories,), + drawer: HomeDrawerWidget( + wooSignalApp: widget.wooSignalApp, + productCategories: _categories, + ), appBar: AppBar( title: StoreLogo(height: 55), centerTitle: true, - actions: [ + actions: [ IconButton( alignment: Alignment.centerLeft, icon: Icon( Icons.search, size: 35, ), - onPressed: () => Navigator.pushNamed(context, "/home-search").then( - (value) => widget.globalKey.currentState!.setState(() {})), + onPressed: () { + routeTo(HomeSearchPage.path); + }, ), - CartIconWidget(key: widget.globalKey), + Flexible(child: NotificationIcon()), + CartIconWidget(), ], ), body: SafeAreaWidget( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: afterLoad(child: () => RefreshableScrollContainer( - controller: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - products: _productLoaderController.getResults(), - onTap: _showProduct, - bannerHeight: MediaQuery.of(context).size.height / 3.5, - bannerImages: bannerImages, - modalBottomSheetMenu: _modalBottomSheetMenu, - )), - flex: 1, - ), - ], + child: NyPullToRefresh.grid( + header: Column( + children: [ + if (bannerImages!.isNotEmpty) + Container( + child: Swiper( + itemBuilder: (BuildContext context, int index) { + return CachedImageWidget( + image: bannerImages[index], + fit: BoxFit.contain, + ); + }, + itemCount: bannerImages.length, + viewportFraction: 0.8, + scale: 0.9, + ), + height: 300, + ), + TopNavWidget(onPressBrowseCategories: _modalBottomSheetMenu), + ], + ), + child: (context, product) { + product as ws_product.Product; + return Container( + height: 300, + child: ProductItemContainer( + product: product, + onTap: () => _showProduct(product), + ), + ); + }, + data: (page) async { + return await appWooSignal((api) => api.getProducts( + perPage: 50, + page: page, + status: "publish", + stockStatus: "instock", + )); + }, ), ), ); } - _onRefresh() async { - _productLoaderController.clear(); - await fetchProducts(); - - setState(() { - _shouldStopRequests = false; - _refreshController.refreshCompleted(resetFooterState: true); - }); - } - - _onLoading() async { - await fetchProducts(); - - if (mounted) { - setState(() {}); - if (_shouldStopRequests) { - _refreshController.loadNoData(); - } else { - _refreshController.loadComplete(); - } - } + _showProduct(ws_product.Product product) { + routeTo(ProductDetailPage.path, data: product); } - - Future fetchProducts() async { - await _productLoaderController.loadProducts( - hasResults: (result) { - if (result == false) { - setState(() { - _shouldStopRequests = true; - }); - return false; - } - return true; - }, - didFinish: () => setState(() {})); - } - - _showProduct(ws_product.Product product) => - Navigator.pushNamed(context, "/product-detail", arguments: product) - .then((value) => widget.globalKey.currentState!.setState(() {})); } diff --git a/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart b/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart index 94b33c6..5e6972c 100644 --- a/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart @@ -16,7 +16,7 @@ class NoResultsForProductsWidget extends StatelessWidget { @override Widget build(BuildContext context) => Column( - children: [ + children: [ Text( trans("No results"), style: Theme.of(context).textTheme.bodyMedium, diff --git a/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart b/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart index 6346af2..65c4830 100644 --- a/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart @@ -9,19 +9,21 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:collection/collection.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/store_logo_widget.dart'; +import '/resources/widgets/notification_icon_widget.dart'; +import '/resources/widgets/product_item_container_widget.dart'; +import '/resources/widgets/no_results_for_products_widget.dart'; +import '/resources/pages/product_detail_page.dart'; +import '/resources/pages/browse_category_page.dart'; import 'package:woosignal/models/response/product_category_collection.dart'; -import '/app/controllers/product_loader_controller.dart'; import '/bootstrap/helpers.dart'; import '/resources/widgets/cached_image_widget.dart'; import '/resources/widgets/home_drawer_widget.dart'; -import '/resources/widgets/no_results_for_products_widget.dart'; import '/resources/widgets/safearea_widget.dart'; import '/resources/widgets/woosignal_ui.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/product_category.dart' as ws_category; import 'package:woosignal/models/response/product.dart' as ws_product; @@ -37,33 +39,32 @@ class NoticHomeWidget extends StatefulWidget { class _NoticHomeWidgetState extends NyState { Widget? activeWidget; - final RefreshController _refreshController = - RefreshController(initialRefresh: false); - - final ProductLoaderController _productLoaderController = - ProductLoaderController(); List _categories = []; - bool _shouldStopRequests = false; - @override boot() async { - await _home(); - } - - _home() async { - await fetchProducts(); await _fetchCategories(); } _fetchCategories() async { if ((widget.wooSignalApp?.productCategoryCollections ?? []).isNotEmpty) { - List productCategoryId = widget.wooSignalApp?.productCategoryCollections.map((e) => int.parse(e.collectionId!)).toList() ?? []; - _categories = await (appWooSignal((api) => - api.getProductCategories(parent: 0, perPage: 50, hideEmpty: true, include: productCategoryId))); + List productCategoryId = widget + .wooSignalApp?.productCategoryCollections + .map((e) => int.parse(e.collectionId!)) + .toList() ?? + []; + _categories = await (appWooSignal((api) => api.getProductCategories( + parent: 0, + perPage: 50, + hideEmpty: true, + include: productCategoryId))); _categories.sort((category1, category2) { - ProductCategoryCollection? productCategoryCollection1 = widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull((element) => element.collectionId == category1.id.toString()); - ProductCategoryCollection? productCategoryCollection2 = widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull((element) => element.collectionId == category2.id.toString()); + ProductCategoryCollection? productCategoryCollection1 = + widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull( + (element) => element.collectionId == category1.id.toString()); + ProductCategoryCollection? productCategoryCollection2 = + widget.wooSignalApp?.productCategoryCollections.firstWhereOrNull( + (element) => element.collectionId == category2.id.toString()); if (productCategoryCollection1 == null) return 0; if (productCategoryCollection2 == null) return 0; @@ -71,7 +72,8 @@ class _NoticHomeWidgetState extends NyState { if (productCategoryCollection1.position == null) return 0; if (productCategoryCollection2.position == null) return 0; - return productCategoryCollection1.position!.compareTo(productCategoryCollection2.position!); + return productCategoryCollection1.position! + .compareTo(productCategoryCollection2.position!); }); } else { _categories = await (appWooSignal((api) => @@ -92,9 +94,7 @@ class _NoticHomeWidgetState extends NyState { title: Text(parseHtmlString(_categories[index].name)), onTap: () { Navigator.pop(context); - Navigator.pushNamed(context, "/browse-category", - arguments: _categories[index]) - .then((value) => setState(() {})); + routeTo(BrowseCategoryPage.path, data: _categories[index]); }, ), ), @@ -103,7 +103,6 @@ class _NoticHomeWidgetState extends NyState { @override Widget build(BuildContext context) { - List products = _productLoaderController.getResults(); return Scaffold( drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp), appBar: AppBar( @@ -124,6 +123,11 @@ class _NoticHomeWidgetState extends NyState { ), ), ), + Flexible( + child: Padding( + child: NotificationIcon(), + padding: EdgeInsets.only(right: 8), + )), ], ), body: SafeAreaWidget( @@ -132,140 +136,78 @@ class _NoticHomeWidgetState extends NyState { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: afterLoad(child: () => ListView( - shrinkWrap: true, - children: [ - Container( - margin: EdgeInsets.only(bottom: 15), - child: Swiper( - itemBuilder: (BuildContext context, int index) { - return CachedImageWidget( - image: - widget.wooSignalApp!.bannerImages![index], - fit: BoxFit.cover, - ); - }, - itemCount: - widget.wooSignalApp!.bannerImages!.length, - viewportFraction: 0.8, - scale: 0.9, - ), - height: MediaQuery.of(context).size.height / 2.5, - ), - Container( - height: 75, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(trans("Must have")), - Flexible( - child: Text( - trans("Our selection of new items"), - style: Theme.of(context) - .textTheme - .headlineMedium, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ) - ], - ), - ), - Container( - height: 380, - child: SmartRefresher( - enablePullDown: true, - enablePullUp: true, - footer: CustomFooter( - builder: - (BuildContext context, LoadStatus? mode) { - Widget body; - if (mode == LoadStatus.idle) { - body = Text(trans("pull up load")); - } else if (mode == LoadStatus.loading) { - body = CupertinoActivityIndicator(); - } else if (mode == LoadStatus.failed) { - body = - Text(trans("Load Failed! Click retry!")); - } else if (mode == LoadStatus.canLoading) { - body = Text(trans("release to load more")); - } else { - return SizedBox.shrink(); - } - return Container( - height: 55.0, - child: Center(child: body), + child: afterLoad( + child: () => ListView( + shrinkWrap: true, + children: [ + Container( + margin: EdgeInsets.only(bottom: 15), + child: Swiper( + itemBuilder: (BuildContext context, int index) { + return CachedImageWidget( + image: widget.wooSignalApp!.bannerImages![index], + fit: BoxFit.cover, ); }, + itemCount: widget.wooSignalApp!.bannerImages!.length, + viewportFraction: 0.8, + scale: 0.9, + ), + height: MediaQuery.of(context).size.height / 2.5, + ), + Container( + height: 75, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(trans("Must have")), + Flexible( + child: Text( + trans("Our selection of new items"), + style: Theme.of(context).textTheme.headlineMedium, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ) + ], ), - controller: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - child: (products.isNotEmpty - ? ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: false, - itemBuilder: (cxt, i) { - return Container( - width: - MediaQuery.of(context).size.width / - 2.5, - child: ProductItemContainer( - product: products[i], - onTap: _showProduct), - ); - }, - itemCount: products.length, - ) - : NoResultsForProductsWidget()), ), - ) - ], + Container( + height: 300, + width: double.infinity, + child: NyPullToRefresh( + scrollDirection: Axis.horizontal, + child: (context, product) { + product as ws_product.Product; + return Container( + height: 300, + width: 300, + child: ProductItemContainer( + product: product, + onTap: () => _showProduct(product)), + ); + }, + data: (page) { + return appWooSignal((api) => api.getProducts( + perPage: 10, + page: page, + status: "publish", + stockStatus: "instock", + )); + }, + empty: NoResultsForProductsWidget(), + )) + ], + ), ), - ),flex: 1,), + flex: 1, + ), ], ), ), ); } - _onRefresh() async { - _productLoaderController.clear(); - await fetchProducts(); - - setState(() { - _shouldStopRequests = false; - _refreshController.refreshCompleted(resetFooterState: true); - }); - } - - _onLoading() async { - await fetchProducts(); - - if (mounted) { - setState(() {}); - if (_shouldStopRequests) { - _refreshController.loadNoData(); - } else { - _refreshController.loadComplete(); - } - } - } - - Future fetchProducts() async { - await _productLoaderController.loadProducts( - hasResults: (result) { - if (result == false) { - setState(() { - _shouldStopRequests = true; - }); - return false; - } - return true; - }, - didFinish: () => setState(() {})); - } - _showProduct(ws_product.Product product) => - Navigator.pushNamed(context, "/product-detail", arguments: product); + routeTo(ProductDetailPage.path, data: product); } diff --git a/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart b/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart index 04a77ae..1a7ca03 100644 --- a/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart @@ -1,5 +1,3 @@ -// -// LabelCore // Label StoreMax // // Created by Anthony Gordon. @@ -9,14 +7,13 @@ // 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:wp_json_api/wp_json_api.dart'; import '/app/models/bottom_nav_item.dart'; import '/bootstrap/app_helper.dart'; -import '/bootstrap/shared_pref/sp_auth.dart'; import '/resources/pages/account_detail_page.dart'; -import '/resources/pages/account_landing_page.dart'; +import '/resources/pages/account_login_page.dart'; import '/resources/pages/cart_page.dart'; import '/resources/pages/wishlist_page_widget.dart'; import '/resources/pages/home_search_page.dart'; @@ -26,32 +23,23 @@ import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; class NoticThemeWidget extends StatefulWidget { - NoticThemeWidget( - {super.key, required this.globalKey, required this.wooSignalApp}); - final GlobalKey globalKey; + NoticThemeWidget({super.key, required this.wooSignalApp}); final WooSignalApp? wooSignalApp; @override createState() => _NoticThemeWidgetState(); } -class _NoticThemeWidgetState extends State { +class _NoticThemeWidgetState extends NyState { Widget? activeWidget; int _currentIndex = 0; List? allNavWidgets; @override - void initState() { - super.initState(); - + init() async { activeWidget = NoticHomeWidget(wooSignalApp: widget.wooSignalApp); - _loadTabs(); - } - - _loadTabs() async { allNavWidgets = await bottomNavWidgets(); - setState(() {}); } @override @@ -115,8 +103,8 @@ class _NoticThemeWidgetState extends State { items.add(BottomNavItem( id: 4, bottomNavigationBarItem: BottomNavigationBarItem( - icon: Icon(Icons.shopping_cart), - label: 'Cart'.tr(), + icon: Icon(Icons.shopping_cart), + label: 'Cart'.tr(), ), tabWidget: CartPage(), )); @@ -124,13 +112,13 @@ class _NoticThemeWidgetState extends State { if (AppHelper.instance.appConfig!.wpLoginEnabled == 1) { items.add(BottomNavItem( id: 5, - bottomNavigationBarItem: - BottomNavigationBarItem(icon: Icon(Icons.person), - label: 'Account'.tr(), - ), - tabWidget: (await authCheck()) + bottomNavigationBarItem: BottomNavigationBarItem( + icon: Icon(Icons.person), + label: 'Account'.tr(), + ), + tabWidget: (await WPJsonAPI.wpUserLoggedIn()) ? AccountDetailPage(showLeadingBackButton: false) - : AccountLandingPage( + : AccountLoginPage( showBackButton: false, ), )); diff --git a/LabelStoreMax/lib/resources/widgets/notification_icon_widget.dart b/LabelStoreMax/lib/resources/widgets/notification_icon_widget.dart new file mode 100644 index 0000000..0b69447 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/notification_icon_widget.dart @@ -0,0 +1,63 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2024, 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 '/bootstrap/helpers.dart'; +import '/resources/pages/notifications_page.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class NotificationIcon extends StatefulWidget { + NotificationIcon({super.key}); + + static String state = "notification_icon"; + + @override + createState() => _NotificationIconState(); +} + +class _NotificationIconState extends NyState { + int totalNotifications = 0; + + _NotificationIconState() { + stateName = NotificationIcon.state; + } + + @override + boot() async { + totalNotifications = + (await NyNotification.allNotificationsNotRead()).length; + } + + @override + stateUpdated(dynamic data) async { + totalNotifications = + (await NyNotification.allNotificationsNotRead()).length; + } + + @override + Widget view(BuildContext context) { + if (!isFirebaseEnabled()) { + return SizedBox.shrink(); + } + if (totalNotifications == 0) { + return InkWell( + onTap: () => routeTo(NotificationsPage.path), + child: Icon(Icons.notifications), + ); + } + return InkWell( + onTap: () => routeTo(NotificationsPage.path), + child: Badge.count( + child: Icon(Icons.notifications), + count: totalNotifications, + ), + ); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/product_detail_body_widget.dart b/LabelStoreMax/lib/resources/widgets/product_detail_body_widget.dart index 67537d4..7744719 100644 --- a/LabelStoreMax/lib/resources/widgets/product_detail_body_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/product_detail_body_widget.dart @@ -9,6 +9,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/product_image_viewer_page.dart'; +import 'package:nylo_framework/nylo_framework.dart'; import '/resources/widgets/product_detail_description_widget.dart'; import '/resources/widgets/product_detail_header_widget.dart'; import '/resources/widgets/product_detail_image_swiper_widget.dart'; @@ -57,9 +59,10 @@ class ProductDetailBodyWidget extends StatelessWidget { ); } - _viewProductImages(BuildContext context, int i) => - Navigator.pushNamed(context, "/product-images", arguments: { - "index": i, - "images": product!.images.map((f) => f.src).toList() - }); + _viewProductImages(BuildContext context, int i) { + routeTo(ProductImageViewerPage.path, data: { + "index": i, + "images": product!.images.map((f) => f.src).toList() + }); + } } diff --git a/LabelStoreMax/lib/resources/widgets/product_detail_related_products_widget.dart b/LabelStoreMax/lib/resources/widgets/product_detail_related_products_widget.dart index 6bc03da..35a8bb2 100644 --- a/LabelStoreMax/lib/resources/widgets/product_detail_related_products_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/product_detail_related_products_widget.dart @@ -9,8 +9,9 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import '/resources/pages/product_detail_page.dart'; +import '/resources/widgets/product_item_container_widget.dart'; import '/bootstrap/helpers.dart'; -import '/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; import 'package:woosignal/models/response/product.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; @@ -63,9 +64,14 @@ class ProductDetailRelatedProductsWidget extends StatelessWidget { shrinkWrap: true, scrollDirection: Axis.horizontal, children: relatedProducts - .map((e) => Container( + .map((product) => Container( width: MediaQuery.of(context).size.width / 2.2, - child: ProductItemContainer(product: e))) + child: ProductItemContainer( + product: product, + onTap: () { + routeTo(ProductDetailPage.path, data: product); + }, + ))) .toList(), ); }, @@ -76,6 +82,10 @@ class ProductDetailRelatedProductsWidget extends StatelessWidget { } Future> fetchRelated() async => await (appWooSignal( - (api) => api.getProducts(perPage: 100, include: product!.relatedIds, status: "publish"), - )); + (api) => api.getProducts( + perPage: 100, + include: product?.relatedIds, + stockStatus: "instock", + status: "publish"), + )); } diff --git a/LabelStoreMax/lib/resources/widgets/product_detail_review_tile_widget.dart b/LabelStoreMax/lib/resources/widgets/product_detail_review_tile_widget.dart index bb86bb5..a346130 100644 --- a/LabelStoreMax/lib/resources/widgets/product_detail_review_tile_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/product_detail_review_tile_widget.dart @@ -19,8 +19,7 @@ class ProductDetailReviewTileWidget extends StatefulWidget { final ProductReview productReview; @override - createState() => - _ProductDetailReviewTileWidgetState(); + createState() => _ProductDetailReviewTileWidgetState(); } class _ProductDetailReviewTileWidgetState diff --git a/LabelStoreMax/lib/resources/widgets/product_detail_reviews_widget.dart b/LabelStoreMax/lib/resources/widgets/product_detail_reviews_widget.dart index 21a3e10..9d8b615 100644 --- a/LabelStoreMax/lib/resources/widgets/product_detail_reviews_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/product_detail_reviews_widget.dart @@ -11,6 +11,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import '/resources/pages/product_reviews_page.dart'; import '/bootstrap/helpers.dart'; import '/resources/widgets/product_detail_review_tile_widget.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart'; @@ -26,8 +27,7 @@ class ProductDetailReviewsWidget extends StatefulWidget { final WooSignalApp? wooSignalApp; @override - createState() => - _ProductDetailReviewsWidgetState(); + createState() => _ProductDetailReviewsWidgetState(); } class _ProductDetailReviewsWidgetState @@ -113,16 +113,14 @@ class _ProductDetailReviewsWidgetState if (reviewsCount >= 5) { childrenWidgets.add( Container( - child: ListTile( - contentPadding: EdgeInsets.symmetric(horizontal: 16), - title: Text( - trans('See More Reviews'), - ), - onTap: () => Navigator.pushNamed( - context, "/product-reviews", - arguments: widget.product), - ), - ), + child: ListTile( + contentPadding: + EdgeInsets.symmetric(horizontal: 16), + title: Text( + trans('See More Reviews'), + ), + onTap: () => routeTo(ProductReviewsPage.path, + data: widget.product))), ); } return ListView( diff --git a/LabelStoreMax/lib/resources/widgets/product_detail_upsell_widget.dart b/LabelStoreMax/lib/resources/widgets/product_detail_upsell_widget.dart index 0c144f2..cf179e6 100644 --- a/LabelStoreMax/lib/resources/widgets/product_detail_upsell_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/product_detail_upsell_widget.dart @@ -9,11 +9,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import '/app/controllers/product_loader_controller.dart'; -import '/resources/widgets/app_loader_widget.dart'; -import '/resources/widgets/woosignal_ui.dart'; +import '/resources/pages/product_detail_page.dart'; +import '/resources/widgets/product_item_container_widget.dart'; +import '/bootstrap/helpers.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:woosignal/models/response/product.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; class ProductDetailUpsellWidget extends StatefulWidget { @@ -23,35 +22,21 @@ class ProductDetailUpsellWidget extends StatefulWidget { final WooSignalApp? wooSignalApp; @override - createState() => - _ProductDetailUpsellWidgetState(); + createState() => _ProductDetailUpsellWidgetState(); } -class _ProductDetailUpsellWidgetState extends State { - final ProductLoaderController _productLoaderController = - ProductLoaderController(); - - bool _isLoading = true; - +class _ProductDetailUpsellWidgetState + extends NyState { @override - void initState() { - super.initState(); - fetchProducts(); - } + boot() async {} @override Widget build(BuildContext context) { - List products = _productLoaderController.getResults(); if (widget.productIds!.isEmpty || - products.isEmpty || widget.wooSignalApp!.showUpsellProducts == false) { return SizedBox.shrink(); } - if (_isLoading == true) { - return AppLoaderWidget(); - } - return ListView( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), @@ -75,39 +60,23 @@ class _ProductDetailUpsellWidgetState extends State { ), ), Container( - height: 300, - child: ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: products - .map( - (e) => Container( + height: 300, + child: NyListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + child: (context, product) { + return Container( width: MediaQuery.of(context).size.width / 2.2, - child: ProductItemContainer(product: e), - ), - ) - .toList(), - ), - ), + child: ProductItemContainer(product: product, onTap: () { + routeTo(ProductDetailPage.path, data: product); + },), + ); + }, + data: () { + return appWooSignal( + (api) => api.getProducts(include: widget.productIds)); + })), ], ); } - - Future fetchProducts() async { - await _productLoaderController.loadProducts( - hasResults: (result) { - if (result == false) { - return false; - } - return true; - }, - didFinish: () { - if (mounted) { - setState(() { - _isLoading = false; - }); - } - }, - productIds: widget.productIds); - } } diff --git a/LabelStoreMax/lib/resources/widgets/product_item_container_widget.dart b/LabelStoreMax/lib/resources/widgets/product_item_container_widget.dart new file mode 100644 index 0000000..0c96794 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/product_item_container_widget.dart @@ -0,0 +1,154 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import '/bootstrap/helpers.dart'; +import '/resources/widgets/cached_image_widget.dart'; +import 'package:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/models/response/product.dart'; + +class ProductItemContainer extends StatelessWidget { + const ProductItemContainer({ + super.key, + this.product, + this.onTap, + }); + + final Product? product; + final Function()? onTap; + + @override + Widget build(BuildContext context) { + if (product == null) { + return SizedBox.shrink(); + } + + double height = 280; + return InkWell( + child: Container( + margin: EdgeInsets.all(4), + child: ListView( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + children: [ + Container( + height: 180, + child: ClipRRect( + borderRadius: BorderRadius.circular(3.0), + child: Stack( + children: [ + Container( + color: Colors.grey[100], + height: double.infinity, + width: double.infinity, + ), + CachedImageWidget( + image: (product!.images.isNotEmpty + ? product!.images.first.src + : getEnv("PRODUCT_PLACEHOLDER_IMAGE")), + fit: BoxFit.contain, + height: height, + width: double.infinity, + ), + if (isProductNew(product)) + Container( + padding: EdgeInsets.all(4), + child: Text( + "New", + style: TextStyle(color: Colors.white), + ), + decoration: BoxDecoration(color: Colors.black), + ), + if (product!.onSale! && product!.type != "variable") + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + padding: EdgeInsets.all(3), + decoration: BoxDecoration( + color: Colors.white70, + ), + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: '', + style: Theme.of(context).textTheme.bodyLarge, + children: [ + TextSpan( + text: + "${workoutSaleDiscount(salePrice: product!.salePrice, priceBefore: product!.regularPrice)}% ${trans("off")}", + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith( + color: Colors.black, + fontSize: 13, + ), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + Container( + margin: const EdgeInsets.only(top: 2, bottom: 2), + child: Text( + product?.name ?? "", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(fontSize: 15), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + Container( + padding: EdgeInsets.only(top: 4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + AutoSizeText( + "${formatStringCurrency(total: product?.price)} ", + style: Theme.of(context) + .textTheme + .bodyLarge! + .copyWith(fontWeight: FontWeight.w800), + textAlign: TextAlign.left, + ), + if ((product?.onSale ?? false) && product?.type != "variable") + RichText( + text: TextSpan(children: [ + TextSpan( + text: '${trans("Was")}: ', + style: + Theme.of(context).textTheme.bodyLarge!.copyWith( + fontSize: 11, + ), + ), + TextSpan( + text: formatStringCurrency( + total: product?.regularPrice, + ), + style: + Theme.of(context).textTheme.bodyLarge!.copyWith( + decoration: TextDecoration.lineThrough, + color: Colors.grey, + fontSize: 11, + ), + ), + ]), + ), + ].toList(), + ), + ), + ], + ), + ), + onTap: onTap, + ); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/product_quantity_widget.dart b/LabelStoreMax/lib/resources/widgets/product_quantity_widget.dart index 895ef8a..01f20cd 100644 --- a/LabelStoreMax/lib/resources/widgets/product_quantity_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/product_quantity_widget.dart @@ -1,8 +1,17 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2024, 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:nylo_framework/nylo_framework.dart'; class ProductQuantity extends StatefulWidget { - ProductQuantity({super.key, required this.productId}); final int productId; @@ -14,7 +23,6 @@ class ProductQuantity extends StatefulWidget { } class _ProductQuantityState extends NyState { - int quantity = 1; late int productId; @@ -22,7 +30,6 @@ class _ProductQuantityState extends NyState { stateName = ProductQuantity.state; } - @override stateUpdated(dynamic data) async { if (productId != data['product_id']) return; diff --git a/LabelStoreMax/lib/resources/widgets/store_logo_widget.dart b/LabelStoreMax/lib/resources/widgets/store_logo_widget.dart new file mode 100644 index 0000000..f350be3 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/store_logo_widget.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/bootstrap/app_helper.dart'; +import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; + +class StoreLogo extends StatelessWidget { + const StoreLogo( + {super.key, + this.height = 100, + this.width = 100, + this.placeholder = const CircularProgressIndicator(), + this.fit = BoxFit.contain, + this.showBgWhite = true}); + + final bool showBgWhite; + final double height; + final double width; + final Widget placeholder; + final BoxFit fit; + + @override + Widget build(BuildContext context) => Container( + decoration: BoxDecoration( + color: showBgWhite ? Colors.white : Colors.transparent, + borderRadius: BorderRadius.circular(5)), + child: CachedImageWidget( + image: AppHelper.instance.appConfig!.appLogo, + height: height, + placeholder: Container(height: height, width: width), + ), + ); +} diff --git a/LabelStoreMax/lib/resources/widgets/toast_notification_widget.dart b/LabelStoreMax/lib/resources/widgets/toast_notification_widget.dart index edb3acd..bb0e315 100644 --- a/LabelStoreMax/lib/resources/widgets/toast_notification_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/toast_notification_widget.dart @@ -1,3 +1,13 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2024, 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:nylo_framework/nylo_framework.dart'; @@ -21,7 +31,9 @@ class ToastNotification extends StatelessWidget { borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( - color: context.isDarkMode ? Colors.black12 : Colors.grey.withOpacity(0.1), + color: context.isDarkMode + ? Colors.black12 + : Colors.grey.withOpacity(0.1), spreadRadius: 3, blurRadius: 5, offset: Offset(0, 2), @@ -42,8 +54,9 @@ class ToastNotification extends StatelessWidget { Container( decoration: BoxDecoration( color: _toastMeta.color, - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(8), topLeft: Radius.circular(8)) - ), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(8), + topLeft: Radius.circular(8))), alignment: Alignment.center, child: Center(child: _toastMeta.icon), padding: EdgeInsets.symmetric(horizontal: 12), @@ -61,7 +74,10 @@ class ToastNotification extends StatelessWidget { style: Theme.of(context) .textTheme .headlineSmall! - .copyWith(color: context.isDarkMode ? Colors.white.withOpacity(0.8) : "#171717".toHexColor()), + .copyWith( + color: context.isDarkMode + ? Colors.white.withOpacity(0.8) + : "#171717".toHexColor()), ).fontWeightBold(), Flexible( child: Text( @@ -71,7 +87,10 @@ class ToastNotification extends StatelessWidget { style: Theme.of(context) .textTheme .bodyLarge! - .copyWith(color: context.isDarkMode ? Colors.white70 : "#5d626b".toHexColor()), + .copyWith( + color: context.isDarkMode + ? Colors.white70 + : "#5d626b".toHexColor()), ), ), ], @@ -91,9 +110,10 @@ class ToastNotification extends StatelessWidget { width: 30, alignment: Alignment.center, decoration: BoxDecoration( - color: context.isDarkMode ? Colors.white30 : "#f2f2f2".toHexColor(), - borderRadius: BorderRadius.circular(20) - ), + color: context.isDarkMode + ? Colors.white30 + : "#f2f2f2".toHexColor(), + borderRadius: BorderRadius.circular(20)), child: Center( child: IconButton( padding: EdgeInsets.zero, @@ -104,9 +124,9 @@ class ToastNotification extends StatelessWidget { }, icon: Icon( Icons.close, - color: context.isDarkMode ? - Colors.white : - "#878787".toHexColor(), + color: context.isDarkMode + ? Colors.white + : "#878787".toHexColor(), size: 18, )), ), @@ -117,4 +137,4 @@ class ToastNotification extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart b/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart index effaff7..8d222a4 100644 --- a/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart +++ b/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart @@ -9,117 +9,13 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '/app/models/cart.dart'; -import '/app/models/cart_line_item.dart'; import '/app/models/checkout_session.dart'; -import '/bootstrap/app_helper.dart'; import '/bootstrap/helpers.dart'; -import '/resources/widgets/cached_image_widget.dart'; -import '/resources/widgets/no_results_for_products_widget.dart'; -import '/resources/widgets/top_nav_widget.dart'; -import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; -import 'package:woosignal/models/response/product.dart'; import 'package:woosignal/models/response/tax_rate.dart'; -class RefreshableScrollContainer extends StatelessWidget { - const RefreshableScrollContainer( - {super.key, - this.controller, - this.onRefresh, - this.onLoading, - this.products, - this.onTap, - this.bannerHeight, - this.bannerImages, - this.modalBottomSheetMenu}); - - final RefreshController? controller; - final Function? onRefresh; - final Function? onLoading; - final List? products; - final Function? onTap; - final double? bannerHeight; - final List? bannerImages; - final Function? modalBottomSheetMenu; - - @override - Widget build(BuildContext context) => SmartRefresher( - enablePullDown: true, - enablePullUp: true, - footer: CustomFooter( - builder: (BuildContext context, LoadStatus? mode) { - Widget body; - if (mode == LoadStatus.idle) { - body = Text(trans("pull up load")); - } else if (mode == LoadStatus.loading) { - body = CupertinoActivityIndicator(); - } else if (mode == LoadStatus.failed) { - body = Text(trans("Load Failed! Click retry!")); - } else if (mode == LoadStatus.canLoading) { - body = Text(trans("release to load more")); - } else { - body = Text(trans("No more products")); - } - return Container( - height: 55.0, - child: Center(child: body), - ); - }, - ), - controller: controller!, - onRefresh: onRefresh as void Function()?, - onLoading: onLoading as void Function()?, - child: (products!.isNotEmpty - ? StaggeredGrid.count( - crossAxisCount: 2, - mainAxisSpacing: 1.0, - crossAxisSpacing: 1.0, - children: [ - if (bannerImages!.isNotEmpty) - StaggeredGridTile.fit( - crossAxisCellCount: 2, - child: Container( - child: Swiper( - itemBuilder: (BuildContext context, int index) { - return CachedImageWidget( - image: bannerImages![index], - fit: BoxFit.contain, - ); - }, - itemCount: bannerImages!.length, - viewportFraction: 0.8, - scale: 0.9, - ), - height: bannerHeight, - )), - StaggeredGridTile.fit( - crossAxisCellCount: 2, - child: TopNavWidget( - onPressBrowseCategories: - modalBottomSheetMenu as dynamic Function()?)), - if (products != null) - ...products! - .map((product) => StaggeredGridTile.fit( - crossAxisCellCount: 1, - child: Container( - height: 300, - child: ProductItemContainer( - product: product, - onTap: onTap, - ), - ))) - - ], - ) - : NoResultsForProductsWidget()), - ); -} - class CheckoutRowLine extends StatelessWidget { const CheckoutRowLine( {super.key, @@ -137,68 +33,67 @@ class CheckoutRowLine extends StatelessWidget { @override Widget build(BuildContext context) => Container( - height: 125, - padding: EdgeInsets.all(8), - decoration: showBorderBottom == true - ? BoxDecoration( - border: Border( - bottom: BorderSide(color: Colors.black12, width: 1), - ), - ) - : BoxDecoration(), - child: InkWell( - onTap: action, - borderRadius: BorderRadius.circular(8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - child: Text( - heading, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(fontSize: 16, fontWeight: FontWeight.bold), - ), - padding: EdgeInsets.only(bottom: 8), - ), - Flexible( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - leadImage, - Expanded( - child: Container( - child: Text( - leadTitle!, - style: - Theme.of(context).textTheme.titleMedium, - maxLines: 2, - overflow: TextOverflow.ellipsis, - softWrap: false, + height: 125, + padding: EdgeInsets.all(8), + decoration: showBorderBottom == true + ? BoxDecoration( + border: Border( + bottom: BorderSide(color: Colors.black12, width: 1), + ), + ) + : BoxDecoration(), + child: InkWell( + onTap: action, + borderRadius: BorderRadius.circular(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + child: Text( + heading, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(fontSize: 16, fontWeight: FontWeight.bold), + ), + padding: EdgeInsets.only(bottom: 8), + ), + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + leadImage, + Expanded( + child: Container( + child: Text( + leadTitle!, + style: Theme.of(context).textTheme.titleMedium, + maxLines: 2, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + padding: EdgeInsets.only(left: 15), + margin: EdgeInsets.only(right: 10), + ), ), - padding: EdgeInsets.only(left: 15), - margin: EdgeInsets.only(right: 10), - ), + ], ), - ], - ), + ), + Icon(Icons.arrow_forward_ios), + ], ), - Icon(Icons.arrow_forward_ios), - ], - ), - ) - ], - ), - ), - ); + ) + ], + ), + ), + ); } class TextEditingRow extends StatelessWidget { @@ -259,15 +154,18 @@ class CheckoutMetaLine extends StatelessWidget { @override Widget build(BuildContext context) => Container( - padding: EdgeInsets.symmetric(horizontal: 8), - child: Row( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( child: Container( child: AutoSizeText(title!, - style: Theme.of(context).textTheme.bodyMedium!.copyWith(fontWeight: FontWeight.bold)), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(fontWeight: FontWeight.bold)), ), flex: 3, ), @@ -280,7 +178,7 @@ class CheckoutMetaLine extends StatelessWidget { ) ], ), - ); + ); } List wsBoxShadow({double? blurRadius}) => [ @@ -295,154 +193,6 @@ List wsBoxShadow({double? blurRadius}) => [ ) ]; -class ProductItemContainer extends StatelessWidget { - const ProductItemContainer({ - super.key, - this.product, - this.onTap, - }); - - final Product? product; - final Function? onTap; - - @override - Widget build(BuildContext context) { - if (product == null) { - return SizedBox.shrink(); - } - - double height = 280; - return InkWell( - child: Container( - margin: EdgeInsets.all(4), - child: ListView( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - children: [ - Container( - height: 180, - child: ClipRRect( - borderRadius: BorderRadius.circular(3.0), - child: Stack( - children: [ - Container( - color: Colors.grey[100], - height: double.infinity, - width: double.infinity, - ), - CachedImageWidget( - image: (product!.images.isNotEmpty - ? product!.images.first.src - : getEnv("PRODUCT_PLACEHOLDER_IMAGE")), - fit: BoxFit.contain, - height: height, - width: double.infinity, - ), - if (isProductNew(product)) - Container(padding: EdgeInsets.all(4), child: Text("New", style: TextStyle(color: Colors.white),), decoration: BoxDecoration(color: Colors.black),), - if (product!.onSale! && product!.type != "variable") - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - padding: EdgeInsets.all(3), - decoration: BoxDecoration( - color: Colors.white70, - ), - child: RichText( - textAlign: TextAlign.center, - text: TextSpan( - text: '', - style: Theme.of(context).textTheme.bodyLarge, - children: [ - TextSpan( - text: - "${workoutSaleDiscount(salePrice: product!.salePrice, priceBefore: product!.regularPrice)}% ${trans("off")}", - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith( - color: Colors.black, - fontSize: 13, - ), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ), - Container( - margin: const EdgeInsets.only(top: 2, bottom: 2), - child: Text( - product!.name!, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(fontSize: 15), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - Container( - padding: EdgeInsets.only(top: 4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - AutoSizeText( - "${formatStringCurrency(total: product!.price)} ", - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith(fontWeight: FontWeight.w800), - textAlign: TextAlign.left, - ), - if (product!.onSale! && product!.type != "variable") - RichText( - text: TextSpan(children: [ - TextSpan( - text: '${trans("Was")}: ', - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith( - fontSize: 11, - ), - ), - TextSpan( - text: formatStringCurrency( - total: product!.regularPrice, - ), - style: Theme.of(context) - .textTheme - .bodyLarge! - .copyWith( - decoration: TextDecoration.lineThrough, - color: Colors.grey, - fontSize: 11, - ), - ), - ]), - ), - ].toList(), - ), - ), - ], - ), - ), - onTap: () => onTap != null - ? onTap!(product) - : Navigator.pushNamed(context, "/product-detail", - arguments: product), - ); - } -} - wsModalBottom(BuildContext context, {String? title, Widget? bodyWidget, Widget? extraWidget}) { showModalBottomSheet( @@ -506,14 +256,14 @@ class CheckoutTotal extends StatelessWidget { @override Widget build(BuildContext context) => NyFutureBuilder( - future: CheckoutSession.getInstance - .total(withFormat: true, taxRate: taxRate), - child: (BuildContext context, data) => Padding( - child: CheckoutMetaLine(title: title, amount: data), - padding: EdgeInsets.only(bottom: 0, top: 15), - ), - loading: SizedBox.shrink(), - ); + future: CheckoutSession.getInstance + .total(withFormat: true, taxRate: taxRate), + child: (BuildContext context, data) => Padding( + child: CheckoutMetaLine(title: title, amount: data), + padding: EdgeInsets.only(bottom: 0, top: 15), + ), + loading: SizedBox.shrink(), + ); } class CheckoutTaxTotal extends StatelessWidget { @@ -527,12 +277,12 @@ class CheckoutTaxTotal extends StatelessWidget { child: (BuildContext context, data) => (data == "0" ? Container() : Padding( - child: CheckoutMetaLine( - title: trans("Tax"), - amount: formatStringCurrency(total: data), - ), - padding: EdgeInsets.only(bottom: 0, top: 0), - )), + child: CheckoutMetaLine( + title: trans("Tax"), + amount: formatStringCurrency(total: data), + ), + padding: EdgeInsets.only(bottom: 0, top: 0), + )), ); } @@ -551,164 +301,6 @@ class CheckoutSubtotal extends StatelessWidget { ), padding: EdgeInsets.only(bottom: 0, top: 0), ), - loading: SizedBox.shrink(), - ); -} - -class CartItemContainer extends StatelessWidget { - const CartItemContainer({ - super.key, - required this.cartLineItem, - required this.actionIncrementQuantity, - required this.actionDecrementQuantity, - required this.actionRemoveItem, - }); - - final CartLineItem cartLineItem; - final void Function() actionIncrementQuantity; - final void Function() actionDecrementQuantity; - final void Function() actionRemoveItem; - - @override - Widget build(BuildContext context) => Container( - margin: EdgeInsets.only(bottom: 7), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Colors.black12, - width: 1, - ), - ), - ), - padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), - child: Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: CachedImageWidget( - image: (cartLineItem.imageSrc == "" - ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") - : cartLineItem.imageSrc), - width: 100, - height: 100, - fit: BoxFit.contain, - ), - flex: 2, - ), - Flexible( - child: Padding( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - cartLineItem.name!, - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.bold), - overflow: TextOverflow.ellipsis, - maxLines: 3, - ), - (cartLineItem.variationOptions != null - ? Text(cartLineItem.variationOptions!, - style: Theme.of(context).textTheme.bodyLarge) - : Container()), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - (cartLineItem.stockStatus == "outofstock" - ? trans("Out of stock") - : trans("In Stock")), - style: (cartLineItem.stockStatus == "outofstock" - ? Theme.of(context).textTheme.bodySmall - : Theme.of(context).textTheme.bodyMedium), - ), - Text( - formatDoubleCurrency( - total: parseWcPrice(cartLineItem.total), - ), - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.bold), - textAlign: TextAlign.center, - ) - ], - ), - ], - ), - padding: EdgeInsets.only(left: 8), - ), - flex: 5, - ) - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: Icon(Icons.remove_circle_outline), - onPressed: actionDecrementQuantity, - highlightColor: Colors.transparent, - ), - Text(cartLineItem.quantity.toString(), - style: Theme.of(context).textTheme.titleLarge), - IconButton( - icon: Icon(Icons.add_circle_outline), - onPressed: actionIncrementQuantity, - highlightColor: Colors.transparent, - ), - ], - ), - IconButton( - alignment: Alignment.centerRight, - icon: Icon(Icons.delete_outline, - color: Colors.deepOrangeAccent, size: 20), - onPressed: actionRemoveItem, - highlightColor: Colors.transparent, - ), - ], - ) - ], - ), - ); -} - -class StoreLogo extends StatelessWidget { - const StoreLogo( - {super.key, - this.height = 100, - this.width = 100, - this.placeholder = const CircularProgressIndicator(), - this.fit = BoxFit.contain, - this.showBgWhite = true}); - - final bool showBgWhite; - final double height; - final double width; - final Widget placeholder; - final BoxFit fit; - - @override - Widget build(BuildContext context) => Container( - decoration: BoxDecoration( - color: showBgWhite ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(5)), - child: CachedImageWidget( - image: AppHelper.instance.appConfig!.appLogo, - height: height, - placeholder: Container(height: height, width: width), - ), + loading: SizedBox.shrink(), ); } diff --git a/LabelStoreMax/lib/routes/router.dart b/LabelStoreMax/lib/routes/router.dart index f204ac9..e9f87a4 100644 --- a/LabelStoreMax/lib/routes/router.dart +++ b/LabelStoreMax/lib/routes/router.dart @@ -1,6 +1,7 @@ +import '/resources/pages/notifications_page.dart'; import '/resources/pages/account_delete_page.dart'; import '/resources/pages/account_detail_page.dart'; -import '/resources/pages/account_landing_page.dart'; +import '/resources/pages/account_login_page.dart'; import '/resources/pages/account_order_detail_page.dart'; import '/resources/pages/account_profile_update_page.dart'; import '/resources/pages/account_register_page.dart'; @@ -29,11 +30,12 @@ import 'package:nylo_framework/nylo_framework.dart'; |-------------------------------------------------------------------------- */ appRouter() => nyRoutes((router) { - router.route(HomePage.path, (context) => HomePage()); + router.route(HomePage.path, (context) => HomePage(), initialRoute: true); router.route(CartPage.path, (context) => CartPage()); - router.route(CheckoutConfirmationPage.path, (context) => CheckoutConfirmationPage()); + router.route(CheckoutConfirmationPage.path, + (context) => CheckoutConfirmationPage()); router.route(BrowseCategoryPage.path, (context) => BrowseCategoryPage(), transition: PageTransitionType.fade); @@ -50,7 +52,8 @@ appRouter() => nyRoutes((router) { router.route(LeaveReviewPage.path, (context) => LeaveReviewPage(), transition: PageTransitionType.rightToLeftWithFade); - router.route(ProductImageViewerPage.path, (context) => ProductImageViewerPage(), + router.route( + ProductImageViewerPage.path, (context) => ProductImageViewerPage(), transition: PageTransitionType.fade); router.route(WishListPageWidget.path, (context) => WishListPageWidget(), @@ -70,8 +73,8 @@ appRouter() => nyRoutes((router) { CheckoutPaymentTypePage.path, (context) => CheckoutPaymentTypePage(), transition: PageTransitionType.bottomToTop); - router.route( - CheckoutShippingTypePage.path, (context) => CheckoutShippingTypePage(), + router.route(CheckoutShippingTypePage.path, + (context) => CheckoutShippingTypePage(), transition: PageTransitionType.bottomToTop); router.route(CouponPage.path, (context) => CouponPage(), @@ -80,24 +83,29 @@ appRouter() => nyRoutes((router) { router.route(HomeSearchPage.path, (context) => HomeSearchPage(), transition: PageTransitionType.bottomToTop); - router.route(CustomerCountriesPage.path, (context) => CustomerCountriesPage(), + router.route( + CustomerCountriesPage.path, (context) => CustomerCountriesPage(), transition: PageTransitionType.bottomToTop); router.route(NoConnectionPage.path, (context) => NoConnectionPage()); // Account Section - router.route(AccountLandingPage.path, (context) => AccountLandingPage(), + router.route(AccountLoginPage.path, (context) => AccountLoginPage(), transition: PageTransitionType.bottomToTop); - router.route(AccountRegistrationPage.path, (context) => AccountRegistrationPage()); + router.route( + AccountRegistrationPage.path, (context) => AccountRegistrationPage()); router.route(AccountDetailPage.path, (context) => AccountDetailPage()); - router.route(AccountProfileUpdatePage.path, (context) => AccountProfileUpdatePage()); + router.route(AccountProfileUpdatePage.path, + (context) => AccountProfileUpdatePage()); router.route(AccountDeletePage.path, (context) => AccountDeletePage()); router.route(AccountShippingDetailsPage.path, (context) => AccountShippingDetailsPage()); -}); + + router.route(NotificationsPage.path, (context) => NotificationsPage()); + }); diff --git a/LabelStoreMax/pubspec.lock b/LabelStoreMax/pubspec.lock index 8542e9d..2fdcf2d 100644 --- a/LabelStoreMax/pubspec.lock +++ b/LabelStoreMax/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "4eec93681221723a686ad580c2e7d960e1017cf1a4e0a263c2573c2c6b0bf5cd" + sha256: "554f148e71e9e016d9c04d4af6b103ca3f74a1ceed7d7307b70a0f41e991eb77" url: "https://pub.dev" source: hosted - version: "1.3.25" + version: "1.3.26" analyzer: dependency: "direct main" description: @@ -221,18 +221,18 @@ packages: dependency: transitive description: name: device_meta - sha256: "47db98335069624bd6538abe5710a89732f27d7e0d1bf681f374a74f4f42b2ef" + sha256: "2b51779008268e90004b21a3920378c69ef7e01acd5bd86402b7ea7c9013d302" url: "https://pub.dev" source: hosted - version: "1.1.12" + version: "1.1.16" dio: dependency: transitive description: name: dio - sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" + sha256: "50fec96118958b97c727d0d8f67255d3683f16cc1f90d9bc917b5d4fe3abeca9" url: "https://pub.dev" source: hosted - version: "5.4.1" + version: "5.4.2" encrypt: dependency: transitive description: @@ -285,10 +285,10 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: "53316975310c8af75a96e365f9fccb67d1c544ef0acdbf0d88bbe30eedd1c4f9" + sha256: "67bf0d5fd78f12f51c6b54a72f6141314136a1a90e98b1b7c45e7fac883254ed" url: "https://pub.dev" source: hosted - version: "2.27.0" + version: "2.27.1" firebase_core_platform_interface: dependency: transitive description: @@ -301,34 +301,34 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492 + sha256: "5377eaac3b9fe8aaf22638d87f92b62784f23572e132dfc029195e84d6cb37de" url: "https://pub.dev" source: hosted - version: "2.11.5" + version: "2.12.0" firebase_messaging: dependency: "direct main" description: name: firebase_messaging - sha256: e41586e0fd04fe9a40424f8b0053d0832e6d04f49e020cdaf9919209a28497e9 + sha256: "34fac43b70d5c41dc864eeb52417128da1f68b0a48604a0c56cd3190f0f609b8" url: "https://pub.dev" source: hosted - version: "14.7.19" + version: "14.7.20" firebase_messaging_platform_interface: dependency: transitive description: name: firebase_messaging_platform_interface - sha256: f7a9d74ff7fc588a924f6b2eaeaa148b0db521b13a9db55f6ad45864fa98c06e + sha256: "1dcf7d0d6776396bb2e488c53b0e4cc671c45a65717a73d881e52190d23aca3c" url: "https://pub.dev" source: hosted - version: "4.5.27" + version: "4.5.28" firebase_messaging_web: dependency: transitive description: name: firebase_messaging_web - sha256: fc21e771166860c55b103701c5ac7cdb2eec28897b97c42e6e5703cbedf9e02e + sha256: ceabccf24d15d03c89dfd6c7eaef11c58fbf00b9c76ebc94028408943b8d2bfd url: "https://pub.dev" source: hosted - version: "3.6.8" + version: "3.7.0" fixnum: dependency: transitive description: @@ -455,10 +455,10 @@ packages: dependency: "direct main" description: name: flutter_spinkit - sha256: b39c753e909d4796906c5696a14daf33639a76e017136c8d82bf3e620ce5bb8e + sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.2.1" flutter_staggered_grid_view: dependency: "direct main" description: @@ -697,18 +697,18 @@ packages: dependency: "direct main" description: name: nylo_framework - sha256: f0767b8acfc8c8770645833d3bf10123ffd609172211f6a2a9acd41a58265e2a + sha256: "6a46d9d48c59aa3e4e50e78dc9b738d4cf98b2cda4abc98cf5fc42a612e730f0" url: "https://pub.dev" source: hosted - version: "5.21.9" + version: "5.24.2" nylo_support: dependency: transitive description: name: nylo_support - sha256: "3e1a303adf0bbe38887534125b17364eeea36543f4e9f8b80a1c8c45de8f8e1d" + sha256: "837ebdc972916006be78d9a77c7ed9c1a99d6266df92dc32cbdd89f56905d617" url: "https://pub.dev" source: hosted - version: "5.53.0" + version: "5.60.0" octo_image: dependency: transitive description: @@ -953,10 +953,10 @@ packages: dependency: transitive description: name: skeletonizer - sha256: "2eb80153c80507359ff05f6a18ed50ae0bafa1b999aa867a8cef0a53387b5650" + sha256: "9a3ae2f4ee4349bdbed3292d04586a1315a44745d2c454684f82f0c46dbeabf9" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" sky_engine: dependency: transitive description: flutter @@ -1206,10 +1206,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.1" win32: dependency: transitive description: @@ -1230,18 +1230,18 @@ packages: dependency: "direct main" description: name: woosignal - sha256: "85a3343bd02163bf78e7cc59877fb4f4c3806bfbfdeb3ca032e9e803585c589f" + sha256: "892db8c07bcfb24fecf855538a24c60a6023942c023eb3142d4604bbeaf6382e" url: "https://pub.dev" source: hosted - version: "3.10.0" + version: "3.13.3" wp_json_api: dependency: "direct main" description: name: wp_json_api - sha256: b633b86ad0f79114197a134359351f587f6373637cbecf055e00f1d025c96a7e + sha256: "07d776aa33ba602315fc7ad3d8f8fd50f13e7594b410854232e44f17cf5a7d35" url: "https://pub.dev" source: hosted - version: "3.3.4" + version: "3.5.1" xdg_directories: dependency: transitive description: @@ -1267,5 +1267,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.3.0 <4.0.0" flutter: ">=3.16.0" diff --git a/LabelStoreMax/pubspec.yaml b/LabelStoreMax/pubspec.yaml index efbf93a..05ef4f2 100644 --- a/LabelStoreMax/pubspec.yaml +++ b/LabelStoreMax/pubspec.yaml @@ -1,7 +1,7 @@ # Official WooSignal App Template for WooCommerce # Label StoreMax -# Version: 6.15.0 +# Version: 7.0.0 # Author: Anthony Gordon # Homepage: https://woosignal.com # Documentation: https://woosignal.com/docs/app/label-storemax @@ -29,9 +29,9 @@ dependencies: google_fonts: ^6.2.0 analyzer: ^5.12.0 intl: ^0.18.0 - nylo_framework: ^5.21.9 - woosignal: ^3.10.0 - wp_json_api: ^3.3.4 + nylo_framework: ^5.24.2 + woosignal: ^3.13.3 + wp_json_api: ^3.5.1 cached_network_image: ^3.3.1 package_info_plus: ^4.2.0 money_formatter: ^0.0.5 @@ -43,15 +43,15 @@ dependencies: status_alert: ^1.0.1 math_expressions: ^2.4.0 validated: ^2.0.0 - flutter_spinkit: ^5.1.0 + flutter_spinkit: ^5.2.1 auto_size_text: ^3.0.0 html: ^0.15.4 flutter_widget_from_html_core: ^0.14.11 flutter_rating_bar: ^4.0.1 flutter_staggered_grid_view: ^0.7.0 flutter_swiper_view: ^1.1.8 - firebase_messaging: ^14.7.19 - firebase_core: ^2.27.0 + firebase_messaging: ^14.7.20 + firebase_core: ^2.27.1 flutter: sdk: flutter flutter_localizations: