v6.3.0 updates
This commit is contained in:
parent
31bb82d49b
commit
683f67877e
@ -1,3 +1,12 @@
|
||||
## [6.3.0] - 2022-11-03
|
||||
|
||||
* Ability to add Menu Links to the drawer widget through the WooSignal dashboard
|
||||
* Fix wording when a shipping zone cannot be found to "Shipping is not supported for your location, sorry"
|
||||
* Update account shipping widget to be uniform with the checkout shipping widget
|
||||
* When logged in, the `CheckoutDetailsPage` will now populate shipping info from the users account
|
||||
* Small refactor to resources/pages
|
||||
* Pubspec.yaml dependency updates
|
||||
|
||||
## [6.2.0] - 2022-09-23
|
||||
|
||||
* Migration to use Nylo v3.4.0
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
# WooCommerce App: Label StoreMax
|
||||
|
||||
### Label StoreMax - v6.2.0
|
||||
### Label StoreMax - v6.3.0
|
||||
|
||||
|
||||
[Official WooSignal WooCommerce App](https://woosignal.com)
|
||||
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "Lösche deinen Account",
|
||||
"Are you sure?": "Bist du dir sicher?",
|
||||
"Yes, delete my account": "Ja, lösche mein Konto",
|
||||
"Account deleted": "Konto gelöscht"
|
||||
"Account deleted": "Konto gelöscht",
|
||||
"Shipping is not supported for your location, sorry": "Der Versand wird für Ihren Standort nicht unterstützt, tut mir leid"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "Delete your account",
|
||||
"Are you sure?": "Are you sure?",
|
||||
"Yes, delete my account": "Yes, delete my account",
|
||||
"Account deleted": "Account deleted"
|
||||
"Account deleted": "Account deleted",
|
||||
"Shipping is not supported for your location, sorry": "Shipping is not supported for your location, sorry"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "eliminar su cuenta",
|
||||
"Are you sure?": "¿Está seguro?",
|
||||
"Yes, delete my account": "Sí, eliminar mi cuenta",
|
||||
"Account deleted": "Cuenta borrada"
|
||||
"Account deleted": "Cuenta borrada",
|
||||
"Shipping is not supported for your location, sorry": "El envío no es compatible para su ubicación, lo siento"
|
||||
}
|
||||
@ -227,5 +227,5 @@
|
||||
"Are you sure?": "Êtes-vous sûr?",
|
||||
"Yes, delete my account": "Oui, supprimer mon compte",
|
||||
"Account deleted": "Compte supprimé",
|
||||
"Phone Number": "Numéro de téléphone"
|
||||
"Shipping is not supported for your location, sorry": "L'expédition n'est pas prise en charge pour votre emplacement, désolé"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "apane khaate ko nasht karo",
|
||||
"Are you sure?": "kya aapako yakeen hai?",
|
||||
"Yes, delete my account": "haan, mera akaunt dileet kar do",
|
||||
"Account deleted": "khaata hataaya gaya"
|
||||
"Account deleted": "khaata hataaya gaya",
|
||||
"Shipping is not supported for your location, sorry": "aapake sthaan ke lie shiping samarthit nahin hai, kshama karen"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "cancella il tuo account",
|
||||
"Are you sure?": "Sei sicuro?",
|
||||
"Yes, delete my account": "Sì, elimina il mio account",
|
||||
"Account deleted": "Account cancellato"
|
||||
"Account deleted": "Account cancellato",
|
||||
"Shipping is not supported for your location, sorry": "La spedizione non è supportata per la tua posizione, mi dispiace"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "Verwijder je account",
|
||||
"Are you sure?": "Weet je het zeker?",
|
||||
"Yes, delete my account": "Ja, verwijder mijn account",
|
||||
"Account deleted": "Account verwijderd"
|
||||
"Account deleted": "Account verwijderd",
|
||||
"Shipping is not supported for your location, sorry": "Verzending wordt niet ondersteund voor uw locatie, sorry"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "Deletar sua conta",
|
||||
"Are you sure?": "Tem certeza?",
|
||||
"Yes, delete my account": "Sim, excluir minha conta",
|
||||
"Account deleted": "Conta excluída"
|
||||
"Account deleted": "Conta excluída",
|
||||
"Shipping is not supported for your location, sorry": "O envio não é suportado para a sua localização, desculpe"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "Hesabını sil",
|
||||
"Are you sure?": "Emin misin?",
|
||||
"Yes, delete my account": "Evet, hesabımı sil",
|
||||
"Account deleted": "Hesap silindi"
|
||||
"Account deleted": "Hesap silindi",
|
||||
"Shipping is not supported for your location, sorry": "Bulunduğunuz yer için gönderim desteklenmiyor, üzgünüm"
|
||||
}
|
||||
@ -226,5 +226,6 @@
|
||||
"Delete your account": "删除您的帐户",
|
||||
"Are you sure?": "你确定吗?",
|
||||
"Yes, delete my account": "是的,删除我的帐户",
|
||||
"Account deleted": "帐号已删除"
|
||||
"Account deleted": "帐号已删除",
|
||||
"Shipping is not supported for your location, sorry": "您所在的位置不支持送货,抱歉"
|
||||
}
|
||||
@ -15,8 +15,41 @@ class BillingDetails {
|
||||
CustomerAddress? shippingAddress;
|
||||
bool? rememberDetails;
|
||||
|
||||
BillingDetails();
|
||||
|
||||
void initSession() {
|
||||
billingAddress = CustomerAddress();
|
||||
shippingAddress = CustomerAddress();
|
||||
}
|
||||
|
||||
Map<String, String?> getShippingAddressStripe() => {
|
||||
"name": shippingAddress?.nameFull(),
|
||||
"line1": shippingAddress!.addressLine,
|
||||
"city": shippingAddress!.city,
|
||||
"postal_code": shippingAddress!.postalCode,
|
||||
"country": (shippingAddress?.customerCountry?.name ?? "")
|
||||
};
|
||||
|
||||
fromWpMeta(Map<String, String> data) async {
|
||||
final Map<String, String> shippingDetailsWpMeta = <String, String>{},
|
||||
billingDetailsWpMeta = <String, String>{};
|
||||
|
||||
shippingDetailsWpMeta.addEntries(data.entries
|
||||
.where((element) => element.key.startsWith("shipping_"))
|
||||
.map((shippingMeta) => MapEntry(
|
||||
shippingMeta.key.replaceAll("shipping_", ""), shippingMeta.value)));
|
||||
billingDetailsWpMeta.addEntries(data.entries
|
||||
.where((element) => element.key.startsWith("billing_"))
|
||||
.map((billingMeta) => MapEntry(
|
||||
billingMeta.key.replaceAll("billing_", ""), billingMeta.value)));
|
||||
|
||||
CustomerAddress billingCustomerAddress = CustomerAddress();
|
||||
await billingCustomerAddress.fromWpMetaData(billingDetailsWpMeta);
|
||||
|
||||
CustomerAddress shippingCustomerAddress = CustomerAddress();
|
||||
await shippingCustomerAddress.fromWpMetaData(shippingDetailsWpMeta);
|
||||
|
||||
billingAddress = billingCustomerAddress;
|
||||
shippingAddress = shippingCustomerAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,9 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter_app/app/models/customer_country.dart';
|
||||
import 'package:flutter_app/app/models/default_shipping.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:wp_json_api/models/wp_meta_meta.dart';
|
||||
|
||||
class CustomerAddress {
|
||||
String? firstName;
|
||||
@ -114,4 +117,62 @@ class CustomerAddress {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
fromWpMetaData(Map<String, dynamic> data) async {
|
||||
if (data.containsKey('first_name')) {
|
||||
firstName = data['first_name'];
|
||||
}
|
||||
|
||||
if (data.containsKey('last_name')) {
|
||||
lastName = data['last_name'];
|
||||
}
|
||||
|
||||
if (data.containsKey('address_1')) {
|
||||
addressLine = data['address_1'];
|
||||
}
|
||||
|
||||
if (data.containsKey('city')) {
|
||||
city = data['city'];
|
||||
}
|
||||
|
||||
if (data.containsKey('postcode')) {
|
||||
postalCode = data['postcode'];
|
||||
}
|
||||
|
||||
if (data.containsKey('email')) {
|
||||
emailAddress = data['email'];
|
||||
}
|
||||
|
||||
if (data.containsKey('phone')) {
|
||||
phoneNumber = data['phone'];
|
||||
}
|
||||
|
||||
if (data.containsKey('country')) {
|
||||
DefaultShipping? defaultShipping =
|
||||
await findCountryMetaForShipping(data['country']);
|
||||
if (defaultShipping == null) {
|
||||
return;
|
||||
}
|
||||
customerCountry = CustomerCountry.fromWpMeta(data, defaultShipping);
|
||||
}
|
||||
}
|
||||
|
||||
List<UserMetaDataItem> toUserMetaDataItem(String type) {
|
||||
return [
|
||||
UserMetaDataItem(key: "${type}_first_name", value: firstName),
|
||||
UserMetaDataItem(key: "${type}_last_name", value: lastName),
|
||||
UserMetaDataItem(key: "${type}_address_1", value: addressLine),
|
||||
UserMetaDataItem(key: "${type}_city", value: city),
|
||||
UserMetaDataItem(key: "${type}_postcode", value: postalCode),
|
||||
UserMetaDataItem(key: "${type}_phone", value: phoneNumber),
|
||||
if (type != "shipping")
|
||||
UserMetaDataItem(key: "${type}_email", value: emailAddress),
|
||||
UserMetaDataItem(
|
||||
key: "${type}_country", value: customerCountry?.countryCode),
|
||||
UserMetaDataItem(
|
||||
key: "${type}_state",
|
||||
value: customerCountry?.state?.code
|
||||
?.replaceAll("${customerCountry?.countryCode}:", "")),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter_app/app/models/default_shipping.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
|
||||
class CustomerCountry {
|
||||
String? countryCode;
|
||||
@ -26,6 +27,14 @@ class CustomerCountry {
|
||||
}
|
||||
}
|
||||
|
||||
CustomerCountry.fromWpMeta(
|
||||
Map<String, dynamic> json, DefaultShipping defaultShipping) {
|
||||
countryCode = json['country'];
|
||||
name = defaultShipping.country;
|
||||
state = findDefaultShippingStateByCode(
|
||||
defaultShipping, "${json['country']}:${json['state']}");
|
||||
}
|
||||
|
||||
CustomerCountry.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) {
|
||||
return;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
@ -37,8 +39,10 @@ class AppProvider implements NyProvider {
|
||||
/// );
|
||||
///
|
||||
/// if (settings.authorizationStatus == AuthorizationStatus.authorized) {
|
||||
/// String token = await messaging.getToken();
|
||||
/// WooSignal.instance.setFcmToken(token);
|
||||
/// String? token = await messaging.getToken();
|
||||
/// if (token != null) {
|
||||
/// WooSignal.instance.setFcmToken(token);
|
||||
/// }
|
||||
/// }
|
||||
|
||||
AppHelper.instance.appConfig = WooSignalApp();
|
||||
@ -70,10 +74,20 @@ class AppProvider implements NyProvider {
|
||||
AppHelper.instance.appConfig = wooSignalApp;
|
||||
|
||||
if (wooSignalApp.wpLoginEnabled == 1) {
|
||||
if (wooSignalApp.wpLoginBaseUrl == null) {
|
||||
AppHelper.instance.appConfig?.wpLoginEnabled = 0;
|
||||
log('Set your stores domain on WooSignal. Go to Features > WP Login and add your domain to "Store Base Url"');
|
||||
}
|
||||
|
||||
if (wooSignalApp.wpLoginWpApiPath == null) {
|
||||
AppHelper.instance.appConfig?.wpLoginEnabled = 0;
|
||||
log('Set your stores Wp JSON path on WooSignal. Go to Features > WP Login and add your Wp JSON path to "WP API Path"');
|
||||
}
|
||||
|
||||
WPJsonAPI.instance.initWith(
|
||||
baseUrl: wooSignalApp.wpLoginBaseUrl!,
|
||||
baseUrl: wooSignalApp.wpLoginBaseUrl ?? "",
|
||||
shouldDebug: getEnv('APP_DEBUG'),
|
||||
wpJsonPath: wooSignalApp.wpLoginWpApiPath!,
|
||||
wpJsonPath: wooSignalApp.wpLoginWpApiPath ?? "",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
import 'package:woosignal/models/response/order.dart';
|
||||
@ -14,7 +14,7 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
import 'package:woosignal/models/response/order.dart';
|
||||
@ -29,8 +29,16 @@ import 'package:woosignal/models/response/tax_rate.dart';
|
||||
//
|
||||
// });
|
||||
|
||||
// REMEMBER TO ADD THIS METHOD E.G. "examplePay" TO THE APP_PAYMENT_METHODS
|
||||
// AS THE PAY METHOD
|
||||
// TO USE A PAYMENT GATEWAY, FIRST OPEN /config/payment_gateways.dart.
|
||||
// THEN ADD A NEW PAYMENT LIKE IN THE BELOW EXAMPLE
|
||||
//
|
||||
// addPayment(
|
||||
// id: 6,
|
||||
// name: "My Payment",
|
||||
// description: trans("Debit or Credit Card"),
|
||||
// assetImage: "payment_logo.png", E.g. /public/assets/images/payment_logo.png
|
||||
// pay: examplePay,
|
||||
// ),
|
||||
|
||||
examplePay(context,
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
@ -15,7 +15,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/cart_line_item.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:flutter_app/resources/widgets/checkout_paypal.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
@ -15,7 +15,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_app/app/models/cart.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:razorpay_flutter/razorpay_flutter.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
@ -24,36 +24,36 @@ import 'package:woosignal/models/response/order.dart';
|
||||
|
||||
razorPay(context,
|
||||
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
|
||||
Razorpay razorpay = Razorpay();
|
||||
Razorpay razorpay = Razorpay();
|
||||
|
||||
razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS,
|
||||
(PaymentSuccessResponse response) async {
|
||||
OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
|
||||
razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS,
|
||||
(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) {
|
||||
Cart.getInstance.clear();
|
||||
Navigator.pushNamed(context, "/checkout-status", arguments: order);
|
||||
} else {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: "Error".tr(),
|
||||
description: trans("Something went wrong, please contact our store"),
|
||||
);
|
||||
state.reloadState(showLoader: false);
|
||||
}
|
||||
});
|
||||
if (order != null) {
|
||||
Cart.getInstance.clear();
|
||||
Navigator.pushNamed(context, "/checkout-status", arguments: order);
|
||||
} else {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: "Error".tr(),
|
||||
description: trans("Something went wrong, please contact our store"),
|
||||
);
|
||||
state.reloadState(showLoader: false);
|
||||
}
|
||||
});
|
||||
|
||||
razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) {
|
||||
showToastNotification(context,
|
||||
title: trans("Error"),
|
||||
description: response.message ?? "",
|
||||
style: ToastNotificationStyleType.WARNING);
|
||||
state.reloadState(showLoader: false);
|
||||
});
|
||||
razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) {
|
||||
showToastNotification(context,
|
||||
title: trans("Error"),
|
||||
description: response.message ?? "",
|
||||
style: ToastNotificationStyleType.WARNING);
|
||||
state.reloadState(showLoader: false);
|
||||
});
|
||||
|
||||
razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
|
||||
razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
|
||||
|
||||
// CHECKOUT HELPER
|
||||
await checkout(taxRate, (total, billingDetails, cart) async {
|
||||
@ -74,8 +74,8 @@ razorPay(context,
|
||||
|
||||
state.reloadState(showLoader: true);
|
||||
|
||||
razorpay.open(options);
|
||||
razorpay.open(options);
|
||||
});
|
||||
}
|
||||
|
||||
void _handleExternalWallet(ExternalWalletResponse response) {}
|
||||
void _handleExternalWallet(ExternalWalletResponse response) {}
|
||||
@ -15,7 +15,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/data/order_wc.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:flutter_stripe/flutter_stripe.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:woosignal/models/payload/order_wc.dart';
|
||||
@ -50,21 +50,13 @@ stripePay(context,
|
||||
dynamic rsp = {};
|
||||
// // CHECKOUT HELPER
|
||||
await checkout(taxRate, (total, billingDetails, cart) async {
|
||||
Map<String, dynamic> address = {
|
||||
"name": billingDetails!.billingAddress?.nameFull(),
|
||||
"line1": billingDetails.shippingAddress!.addressLine,
|
||||
"city": billingDetails.shippingAddress!.city,
|
||||
"postal_code": billingDetails.shippingAddress!.postalCode,
|
||||
"country": (billingDetails.shippingAddress?.customerCountry?.name ?? "")
|
||||
};
|
||||
|
||||
String cartShortDesc = await cart.cartShortDesc();
|
||||
|
||||
rsp = await appWooSignal((api) => api.stripePaymentIntent(
|
||||
amount: total,
|
||||
email: billingDetails.billingAddress?.emailAddress,
|
||||
email: billingDetails?.billingAddress?.emailAddress,
|
||||
desc: cartShortDesc,
|
||||
shipping: address,
|
||||
shipping: billingDetails?.getShippingAddressStripe(),
|
||||
));
|
||||
});
|
||||
|
||||
@ -40,7 +40,9 @@ import 'package:status_alert/status_alert.dart';
|
||||
import 'package:woosignal/models/response/products.dart';
|
||||
import 'package:woosignal/models/response/tax_rate.dart';
|
||||
import 'package:woosignal/woosignal.dart';
|
||||
import 'package:wp_json_api/models/responses/wp_user_info_response.dart';
|
||||
import '../resources/themes/styles/color_styles.dart';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
|
||||
Future<User?> getUser() async =>
|
||||
(await (NyStorage.read<User>(SharedKey.authUser, model: User())));
|
||||
@ -498,9 +500,8 @@ class UserAuth {
|
||||
String redirect = "/home";
|
||||
}
|
||||
|
||||
Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async {
|
||||
String data = await DefaultAssetBundle.of(context)
|
||||
.loadString("public/assets/json/default_shipping.json");
|
||||
Future<List<DefaultShipping>> getDefaultShipping() async {
|
||||
String data = await rootBundle.loadString('public/assets/json/default_shipping.json');
|
||||
dynamic dataJson = json.decode(data);
|
||||
List<DefaultShipping> shipping = [];
|
||||
|
||||
@ -518,6 +519,37 @@ Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async {
|
||||
return shipping;
|
||||
}
|
||||
|
||||
Future<DefaultShipping?> findCountryMetaForShipping(String countryCode) async {
|
||||
List<DefaultShipping> defaultShipping = await getDefaultShipping();
|
||||
List<DefaultShipping> shippingByCountryCode = defaultShipping.where((element) => element.code == countryCode).toList();
|
||||
if (shippingByCountryCode.isNotEmpty) {
|
||||
return shippingByCountryCode.first;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
DefaultShippingState? findDefaultShippingStateByCode(DefaultShipping defaultShipping, String code) {
|
||||
List<DefaultShippingState> defaultShippingStates = defaultShipping.states.where((state) => state.code == code).toList();
|
||||
if (defaultShippingStates.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
DefaultShippingState defaultShippingState = defaultShippingStates.first;
|
||||
return DefaultShippingState(code: defaultShippingState.code, name: defaultShippingState.name);
|
||||
}
|
||||
|
||||
bool hasKeyInMeta(WPUserInfoResponse wpUserInfoResponse, String key) {
|
||||
return (wpUserInfoResponse.data!.metaData ?? []).where((meta) => meta.key == key).toList().isNotEmpty;
|
||||
}
|
||||
|
||||
String fetchValueInMeta(WPUserInfoResponse wpUserInfoResponse, String key) {
|
||||
String value = "";
|
||||
List<dynamic>? metaDataValue = (wpUserInfoResponse.data!.metaData ?? []).where((meta) => meta.key == key).first.value;
|
||||
if (metaDataValue != null && metaDataValue.isNotEmpty) {
|
||||
return metaDataValue.first ?? "";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
String truncateString(String data, int length) {
|
||||
return (data.length >= length) ? '${data.substring(0, length)}...' : data;
|
||||
}
|
||||
@ -560,6 +592,45 @@ removeWishlistProduct({required Product? product}) async {
|
||||
await NyStorage.store(SharedKey.wishlistProducts, json);
|
||||
}
|
||||
|
||||
Future<BillingDetails> billingDetailsFromWpUserInfoResponse(wpUserInfoResponse) async {
|
||||
List<String> metaDataAddress = [
|
||||
'billing_first_name',
|
||||
'billing_last_name',
|
||||
'billing_company',
|
||||
'billing_address_1',
|
||||
'billing_address_2',
|
||||
'billing_city',
|
||||
'billing_postcode',
|
||||
'billing_country',
|
||||
'billing_state',
|
||||
'billing_phone',
|
||||
'billing_email',
|
||||
'shipping_first_name',
|
||||
'shipping_last_name',
|
||||
'shipping_company',
|
||||
'shipping_address_1',
|
||||
'shipping_address_2',
|
||||
'shipping_city',
|
||||
'shipping_postcode',
|
||||
'shipping_country',
|
||||
'shipping_state',
|
||||
'shipping_phone',
|
||||
];
|
||||
|
||||
Map<String, String> metaData = {};
|
||||
|
||||
for (var dataKey in metaDataAddress) {
|
||||
if (hasKeyInMeta(wpUserInfoResponse, dataKey)) {
|
||||
String value = fetchValueInMeta(wpUserInfoResponse, dataKey);
|
||||
metaData.addAll({dataKey: value});
|
||||
}
|
||||
}
|
||||
|
||||
BillingDetails billingDetails = BillingDetails();
|
||||
await billingDetails.fromWpMeta(metaData);
|
||||
return billingDetails;
|
||||
}
|
||||
|
||||
/// API helper
|
||||
api<T>(dynamic Function(T) request, {BuildContext? context}) async =>
|
||||
await nyApi<T>(
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import 'package:flutter_app/app/models/payment_type.dart';
|
||||
import 'package:flutter_app/app/providers/cash_on_delivery.dart';
|
||||
import 'package:flutter_app/app/providers/paypal_pay.dart';
|
||||
import 'package:flutter_app/app/providers/razorpay_pay.dart';
|
||||
import 'package:flutter_app/app/providers/stripe_pay.dart';
|
||||
import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart';
|
||||
import 'package:flutter_app/app/providers/payments/paypal_pay.dart';
|
||||
import 'package:flutter_app/app/providers/payments/razorpay_pay.dart';
|
||||
import 'package:flutter_app/app/providers/payments/stripe_pay.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
|
||||
|
||||
@ -1,234 +0,0 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:wp_json_api/models/responses/wc_customer_info_response.dart';
|
||||
import 'package:wp_json_api/models/responses/wc_customer_updated_response.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
class AccountBillingDetailsPage extends StatefulWidget {
|
||||
AccountBillingDetailsPage();
|
||||
|
||||
@override
|
||||
_AccountBillingDetailsPageState createState() =>
|
||||
_AccountBillingDetailsPageState();
|
||||
}
|
||||
|
||||
class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
|
||||
_AccountBillingDetailsPageState();
|
||||
|
||||
// BILLING TEXT CONTROLLERS
|
||||
final TextEditingController _txtShippingFirstName = TextEditingController(),
|
||||
_txtShippingLastName = TextEditingController(),
|
||||
_txtShippingAddressLine = TextEditingController(),
|
||||
_txtShippingCity = TextEditingController(),
|
||||
_txtShippingState = TextEditingController(),
|
||||
_txtShippingPostalCode = TextEditingController(),
|
||||
_txtShippingCountry = TextEditingController();
|
||||
|
||||
bool _isLoading = true, _isUpdating = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fetchUserDetails();
|
||||
}
|
||||
|
||||
_fetchUserDetails() async {
|
||||
WCCustomerInfoResponse wcCustomerInfoResponse =
|
||||
await WPJsonAPI.instance.api((request) async {
|
||||
return request.wcCustomerInfo((await readAuthToken())!);
|
||||
});
|
||||
|
||||
Billing billing = wcCustomerInfoResponse.data!.billing!;
|
||||
_txtShippingFirstName.text = billing.firstName!;
|
||||
_txtShippingLastName.text = billing.lastName!;
|
||||
|
||||
_txtShippingAddressLine.text = billing.address1!;
|
||||
_txtShippingCity.text = billing.city!;
|
||||
_txtShippingState.text = billing.state!;
|
||||
_txtShippingPostalCode.text = billing.postcode!;
|
||||
_txtShippingCountry.text = billing.country!;
|
||||
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: Text(trans("Billing Details")),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||
child: _isLoading
|
||||
? AppLoaderWidget()
|
||||
: LayoutBuilder(
|
||||
builder: (context, constraints) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("First Name"),
|
||||
controller: _txtShippingFirstName,
|
||||
shouldAutoFocus: true,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Last Name"),
|
||||
controller: _txtShippingLastName,
|
||||
),
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
),
|
||||
TextEditingRow(
|
||||
heading: trans("Address Line"),
|
||||
controller: _txtShippingAddressLine,
|
||||
),
|
||||
Row(children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("City"),
|
||||
controller: _txtShippingCity,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("State"),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: _txtShippingState),
|
||||
),
|
||||
]),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Postal code"),
|
||||
controller: _txtShippingPostalCode,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Country"),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: _txtShippingCountry,
|
||||
),
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
)
|
||||
],
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: ThemeColor.get(context).surfaceBackground,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? wsBoxShadow()
|
||||
: null,
|
||||
),
|
||||
padding: EdgeInsets.all(8),
|
||||
),
|
||||
height:
|
||||
(constraints.maxHeight - constraints.minHeight) *
|
||||
0.6,
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
PrimaryButton(
|
||||
title: trans("UPDATE DETAILS"),
|
||||
isLoading: _isUpdating,
|
||||
action: _updateBillingDetails,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_updateBillingDetails() async {
|
||||
String firstName = _txtShippingFirstName.text;
|
||||
String lastName = _txtShippingLastName.text;
|
||||
String addressLine = _txtShippingAddressLine.text;
|
||||
String city = _txtShippingCity.text;
|
||||
String state = _txtShippingState.text;
|
||||
String postalCode = _txtShippingPostalCode.text;
|
||||
String country = _txtShippingCountry.text;
|
||||
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
setState(() {
|
||||
_isUpdating = true;
|
||||
});
|
||||
|
||||
WCCustomerUpdatedResponse? wcCustomerUpdatedResponse;
|
||||
try {
|
||||
wcCustomerUpdatedResponse = await WPJsonAPI.instance.api((request) =>
|
||||
request.wcUpdateCustomerInfo(userToken,
|
||||
billingFirstName: firstName,
|
||||
billingLastName: lastName,
|
||||
billingAddress1: addressLine,
|
||||
billingCity: city,
|
||||
billingState: state,
|
||||
billingPostcode: postalCode,
|
||||
billingCountry: country));
|
||||
} on Exception catch (_) {
|
||||
showToastNotification(context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER);
|
||||
} finally {
|
||||
setState(() {
|
||||
_isUpdating = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (wcCustomerUpdatedResponse != null &&
|
||||
wcCustomerUpdatedResponse.status == 200) {
|
||||
showToastNotification(context,
|
||||
title: trans("Success"),
|
||||
description: trans("Account updated"),
|
||||
style: ToastNotificationStyleType.SUCCESS);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,17 +8,14 @@ import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
class AccountDeletePage extends StatefulWidget {
|
||||
AccountDeletePage({Key? key}) : super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
_AccountDeletePageState createState() => _AccountDeletePageState();
|
||||
}
|
||||
|
||||
class _AccountDeletePageState extends NyState<AccountDeletePage> {
|
||||
|
||||
@override
|
||||
init() async {
|
||||
|
||||
}
|
||||
init() async {}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@ -33,33 +30,39 @@ class _AccountDeletePageState extends NyState<AccountDeletePage> {
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.no_accounts_rounded, size: 50),
|
||||
Text(
|
||||
trans("Delete your account"),
|
||||
style: textTheme.headline3,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 18),
|
||||
child: Text(trans("Are you sure?")),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.no_accounts_rounded, size: 50),
|
||||
Text(trans("Delete your account"), style: textTheme.headline3,),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 18),
|
||||
child: Text(trans("Are you sure?")),
|
||||
),
|
||||
],),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
PrimaryButton(title: trans("Yes, delete my account"), isLoading: isLocked('delete_account'), action: _deleteAccount),
|
||||
LinkButton(title: trans("Back"), action: pop)
|
||||
],
|
||||
)
|
||||
PrimaryButton(
|
||||
title: trans("Yes, delete my account"),
|
||||
isLoading: isLocked('delete_account'),
|
||||
action: _deleteAccount),
|
||||
LinkButton(title: trans("Back"), action: pop)
|
||||
],
|
||||
)
|
||||
),
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@ -70,9 +73,7 @@ class _AccountDeletePageState extends NyState<AccountDeletePage> {
|
||||
WPUserDeleteResponse? wpUserDeleteResponse;
|
||||
try {
|
||||
wpUserDeleteResponse = await WPJsonAPI.instance
|
||||
.api((request) => request.wpUserDelete(
|
||||
userToken
|
||||
));
|
||||
.api((request) => request.wpUserDelete(userToken));
|
||||
} on Exception catch (e) {
|
||||
NyLogger.error(e.toString());
|
||||
showToastNotification(
|
||||
@ -84,7 +85,8 @@ class _AccountDeletePageState extends NyState<AccountDeletePage> {
|
||||
}
|
||||
|
||||
if (wpUserDeleteResponse != null) {
|
||||
showToast(title: trans("Success"), description: trans("Account deleted"));
|
||||
showToast(
|
||||
title: trans("Success"), description: trans("Account deleted"));
|
||||
await authLogout(context);
|
||||
}
|
||||
});
|
||||
|
||||
@ -156,8 +156,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
|
||||
child: Padding(
|
||||
child: Text(
|
||||
[userFirstName, userLastName]
|
||||
.where(
|
||||
(t) => (t != null || t != ""))
|
||||
.where((t) => (t != null || t != ""))
|
||||
.toList()
|
||||
.join(" "),
|
||||
style: TextStyle(
|
||||
@ -32,7 +32,6 @@ class AccountLandingPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AccountLandingPageState extends NyState<AccountLandingPage> {
|
||||
|
||||
final TextEditingController _tfEmailController = TextEditingController(),
|
||||
_tfPasswordController = TextEditingController();
|
||||
|
||||
@ -226,19 +225,18 @@ class _AccountLandingPageState extends NyState<AccountLandingPage> {
|
||||
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);
|
||||
|
||||
showToastNotification(context,
|
||||
title: trans("Hello"),
|
||||
description: trans("Welcome back"),
|
||||
style: ToastNotificationStyleType.SUCCESS,
|
||||
icon: Icons.account_circle);
|
||||
navigatorPush(context,
|
||||
routeName: UserAuth.instance.redirect, forgetLast: 1);
|
||||
String? token = wpUserLoginResponse.data!.userToken;
|
||||
String userId = wpUserLoginResponse.data!.userId.toString();
|
||||
User user = User.fromUserAuthResponse(token: token, userId: userId);
|
||||
await user.save(SharedKey.authUser);
|
||||
|
||||
showToastNotification(context,
|
||||
title: trans("Hello"),
|
||||
description: trans("Welcome back"),
|
||||
style: ToastNotificationStyleType.SUCCESS,
|
||||
icon: Icons.account_circle);
|
||||
navigatorPush(context,
|
||||
routeName: UserAuth.instance.redirect, forgetLast: 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -114,7 +114,8 @@ class _AccountRegistrationPageState extends NyState<AccountRegistrationPage> {
|
||||
child: InkWell(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: '${trans("By tapping \"Register\" you agree to ")} ${AppHelper.instance.appConfig!.appName!}\'s ',
|
||||
text:
|
||||
'${trans("By tapping \"Register\" you agree to ")} ${AppHelper.instance.appConfig!.appName!}\'s ',
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: trans("terms and conditions"),
|
||||
@ -175,16 +176,20 @@ class _AccountRegistrationPageState extends NyState<AccountRegistrationPage> {
|
||||
WPUserRegisterResponse? wpUserRegisterResponse;
|
||||
try {
|
||||
wpUserRegisterResponse = await WPJsonAPI.instance.api(
|
||||
(request) => request.wpRegister(
|
||||
(request) => request.wpRegister(
|
||||
email: email.toLowerCase(),
|
||||
password: password,
|
||||
username: username,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
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"));
|
||||
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,
|
||||
@ -195,7 +200,7 @@ class _AccountRegistrationPageState extends NyState<AccountRegistrationPage> {
|
||||
showToastNotification(context,
|
||||
title: trans("Invalid details"),
|
||||
description:
|
||||
trans("Something went wrong, please contact our store"),
|
||||
trans("Something went wrong, please contact our store"),
|
||||
style: ToastNotificationStyleType.DANGER);
|
||||
} on ExistingUserLoginException catch (_) {
|
||||
showToastNotification(context,
|
||||
@ -233,21 +238,21 @@ class _AccountRegistrationPageState extends NyState<AccountRegistrationPage> {
|
||||
}
|
||||
|
||||
// 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);
|
||||
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));
|
||||
await WPJsonAPI.instance.api((request) => request.wpUpdateUserInfo(token,
|
||||
firstName: firstName, lastName: lastName));
|
||||
|
||||
showToastNotification(context,
|
||||
title: "${trans("Hello")} $firstName",
|
||||
description: trans("you're now logged in"),
|
||||
style: ToastNotificationStyleType.SUCCESS,
|
||||
icon: Icons.account_circle);
|
||||
navigatorPush(context,
|
||||
routeName: UserAuth.instance.redirect, forgetLast: 2);
|
||||
showToastNotification(context,
|
||||
title: "${trans("Hello")} $firstName",
|
||||
description: trans("you're now logged in"),
|
||||
style: ToastNotificationStyleType.SUCCESS,
|
||||
icon: Icons.account_circle);
|
||||
navigatorPush(context,
|
||||
routeName: UserAuth.instance.redirect, forgetLast: 2);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,258 +0,0 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:wp_json_api/models/responses/wc_customer_info_response.dart';
|
||||
import 'package:wp_json_api/models/responses/wc_customer_updated_response.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
|
||||
class AccountShippingDetailsPage extends StatefulWidget {
|
||||
AccountShippingDetailsPage();
|
||||
|
||||
@override
|
||||
_AccountShippingDetailsPageState createState() =>
|
||||
_AccountShippingDetailsPageState();
|
||||
}
|
||||
|
||||
class _AccountShippingDetailsPageState
|
||||
extends State<AccountShippingDetailsPage> {
|
||||
_AccountShippingDetailsPageState();
|
||||
|
||||
// BILLING TEXT CONTROLLERS
|
||||
final TextEditingController _txtShippingFirstName = TextEditingController(),
|
||||
_txtShippingLastName = TextEditingController(),
|
||||
_txtShippingAddressLine = TextEditingController(),
|
||||
_txtShippingCity = TextEditingController(),
|
||||
_txtShippingPostalCode = TextEditingController(),
|
||||
_txtShippingState = TextEditingController(),
|
||||
_txtShippingCountry = TextEditingController();
|
||||
|
||||
bool _isLoading = true, _isUpdating = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_fetchUserDetails();
|
||||
}
|
||||
|
||||
_fetchUserDetails() async {
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
WCCustomerInfoResponse? wcCustomerInfoResponse;
|
||||
try {
|
||||
wcCustomerInfoResponse = await WPJsonAPI.instance
|
||||
.api((request) => request.wcCustomerInfo(userToken!));
|
||||
} on Exception catch (_) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
return;
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (wcCustomerInfoResponse != null &&
|
||||
wcCustomerInfoResponse.status == 200) {
|
||||
Shipping shipping = wcCustomerInfoResponse.data!.shipping!;
|
||||
_txtShippingFirstName.text = shipping.firstName!;
|
||||
_txtShippingLastName.text = shipping.lastName!;
|
||||
|
||||
_txtShippingAddressLine.text = shipping.address1!;
|
||||
_txtShippingCity.text = shipping.city!;
|
||||
_txtShippingState.text = shipping.state!;
|
||||
_txtShippingPostalCode.text = shipping.postcode!;
|
||||
_txtShippingCountry.text = shipping.country!;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: Text(trans("Shipping Details")),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
},
|
||||
child: _isLoading
|
||||
? AppLoaderWidget()
|
||||
: LayoutBuilder(
|
||||
builder: (context, constraints) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
SizedBox(
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("First Name"),
|
||||
controller: _txtShippingFirstName,
|
||||
shouldAutoFocus: true,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Last Name"),
|
||||
controller: _txtShippingLastName,
|
||||
),
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
),
|
||||
TextEditingRow(
|
||||
heading: trans("Address Line"),
|
||||
controller: _txtShippingAddressLine,
|
||||
),
|
||||
Row(children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("City"),
|
||||
controller: _txtShippingCity,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("State"),
|
||||
controller: _txtShippingState,
|
||||
),
|
||||
),
|
||||
]),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Postal code"),
|
||||
controller: _txtShippingPostalCode,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Country"),
|
||||
controller: _txtShippingCountry,
|
||||
),
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceEvenly,
|
||||
)
|
||||
],
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: ThemeColor.get(context).surfaceBackground,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? wsBoxShadow()
|
||||
: null,
|
||||
),
|
||||
padding: EdgeInsets.all(8),
|
||||
),
|
||||
height:
|
||||
(constraints.maxHeight - constraints.minHeight) *
|
||||
0.6,
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
PrimaryButton(
|
||||
title: trans("UPDATE DETAILS"),
|
||||
isLoading: _isUpdating,
|
||||
action: _updateShippingDetails,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_updateShippingDetails() async {
|
||||
String firstName = _txtShippingFirstName.text;
|
||||
String lastName = _txtShippingLastName.text;
|
||||
String addressLine = _txtShippingAddressLine.text;
|
||||
String city = _txtShippingCity.text;
|
||||
String state = _txtShippingState.text;
|
||||
String postalCode = _txtShippingPostalCode.text;
|
||||
String country = _txtShippingCountry.text;
|
||||
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
if (_isUpdating == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isUpdating = true;
|
||||
});
|
||||
|
||||
WCCustomerUpdatedResponse? wcCustomerUpdatedResponse;
|
||||
try {
|
||||
wcCustomerUpdatedResponse = await WPJsonAPI.instance.api(
|
||||
(request) => request.wcUpdateCustomerInfo(
|
||||
userToken,
|
||||
shippingFirstName: firstName,
|
||||
shippingLastName: lastName,
|
||||
shippingAddress1: addressLine,
|
||||
shippingCity: city,
|
||||
shippingState: state,
|
||||
shippingPostcode: postalCode,
|
||||
shippingCountry: country,
|
||||
),
|
||||
);
|
||||
} on Exception catch (_) {
|
||||
showToastNotification(context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER);
|
||||
} finally {
|
||||
setState(() {
|
||||
_isUpdating = true;
|
||||
});
|
||||
}
|
||||
|
||||
if (wcCustomerUpdatedResponse != null &&
|
||||
wcCustomerUpdatedResponse.status == 200) {
|
||||
showToastNotification(context,
|
||||
title: trans("Success"),
|
||||
description: trans("Account updated"),
|
||||
style: ToastNotificationStyleType.SUCCESS);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,377 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/billing_details.dart';
|
||||
import 'package:flutter_app/app/models/customer_address.dart';
|
||||
import 'package:flutter_app/app/models/customer_country.dart';
|
||||
import 'package:flutter_app/app/models/default_shipping.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/customer_address_input.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/switch_address_tab.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:wp_json_api/models/responses/wp_user_info_response.dart';
|
||||
import 'package:wp_json_api/models/responses/wp_user_info_updated_response.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
import 'package:validated/validated.dart' as validate;
|
||||
|
||||
class AccountShippingDetailsPage extends StatefulWidget {
|
||||
AccountShippingDetailsPage();
|
||||
|
||||
@override
|
||||
_AccountShippingDetailsPageState createState() =>
|
||||
_AccountShippingDetailsPageState();
|
||||
}
|
||||
|
||||
class _AccountShippingDetailsPageState
|
||||
extends NyState<AccountShippingDetailsPage> {
|
||||
_AccountShippingDetailsPageState();
|
||||
|
||||
int activeTabIndex = 0;
|
||||
|
||||
// TEXT CONTROLLERS
|
||||
final TextEditingController
|
||||
// billing
|
||||
_txtBillingFirstName = TextEditingController(),
|
||||
_txtBillingLastName = TextEditingController(),
|
||||
_txtBillingAddressLine = TextEditingController(),
|
||||
_txtBillingCity = TextEditingController(),
|
||||
_txtBillingPostalCode = TextEditingController(),
|
||||
_txtBillingEmailAddress = TextEditingController(),
|
||||
_txtBillingPhoneNumber = TextEditingController(),
|
||||
// shipping
|
||||
_txtShippingFirstName = TextEditingController(),
|
||||
_txtShippingLastName = TextEditingController(),
|
||||
_txtShippingAddressLine = TextEditingController(),
|
||||
_txtShippingCity = TextEditingController(),
|
||||
_txtShippingPostalCode = TextEditingController();
|
||||
|
||||
CustomerCountry? _billingCountry, _shippingCountry;
|
||||
|
||||
Widget? activeTab;
|
||||
|
||||
Widget tabShippingDetails() => CustomerAddressInput(
|
||||
txtControllerFirstName: _txtShippingFirstName,
|
||||
txtControllerLastName: _txtShippingLastName,
|
||||
txtControllerAddressLine: _txtShippingAddressLine,
|
||||
txtControllerCity: _txtShippingCity,
|
||||
txtControllerPostalCode: _txtShippingPostalCode,
|
||||
customerCountry: _shippingCountry,
|
||||
onTapCountry: () => _navigateToSelectCountry(type: "shipping"));
|
||||
|
||||
Widget tabBillingDetails() => CustomerAddressInput(
|
||||
txtControllerFirstName: _txtBillingFirstName,
|
||||
txtControllerLastName: _txtBillingLastName,
|
||||
txtControllerAddressLine: _txtBillingAddressLine,
|
||||
txtControllerCity: _txtBillingCity,
|
||||
txtControllerPostalCode: _txtBillingPostalCode,
|
||||
txtControllerEmailAddress: _txtBillingEmailAddress,
|
||||
txtControllerPhoneNumber: _txtBillingPhoneNumber,
|
||||
customerCountry: _billingCountry,
|
||||
onTapCountry: () => _navigateToSelectCountry(type: "billing"),
|
||||
);
|
||||
|
||||
@override
|
||||
init() async {
|
||||
super.init();
|
||||
|
||||
await awaitData(perform: () async {
|
||||
await _fetchUserDetails();
|
||||
});
|
||||
}
|
||||
|
||||
_setFieldsFromCustomerAddress(CustomerAddress? customerAddress,
|
||||
{required String type}) {
|
||||
assert(type != "");
|
||||
if (customerAddress == null) {
|
||||
return;
|
||||
}
|
||||
_setFields(
|
||||
firstName: customerAddress.firstName,
|
||||
lastName: customerAddress.lastName,
|
||||
addressLine: customerAddress.addressLine,
|
||||
city: customerAddress.city,
|
||||
postalCode: customerAddress.postalCode,
|
||||
emailAddress: customerAddress.emailAddress,
|
||||
phoneNumber: customerAddress.phoneNumber,
|
||||
customerCountry: customerAddress.customerCountry,
|
||||
type: type,
|
||||
);
|
||||
}
|
||||
|
||||
_setFields(
|
||||
{required String? firstName,
|
||||
required String? lastName,
|
||||
required String? addressLine,
|
||||
required String? city,
|
||||
required String? postalCode,
|
||||
required String? emailAddress,
|
||||
required String? phoneNumber,
|
||||
required CustomerCountry? customerCountry,
|
||||
String? type}) {
|
||||
if (type == "billing") {
|
||||
_txtBillingFirstName.text = firstName ?? "";
|
||||
_txtBillingLastName.text = lastName ?? "";
|
||||
_txtBillingAddressLine.text = addressLine ?? "";
|
||||
_txtBillingCity.text = city ?? "";
|
||||
_txtBillingPostalCode.text = postalCode ?? "";
|
||||
_txtBillingPhoneNumber.text = phoneNumber ?? "";
|
||||
_txtBillingEmailAddress.text = emailAddress ?? "";
|
||||
_billingCountry = customerCountry;
|
||||
} else if (type == "shipping") {
|
||||
_txtShippingFirstName.text = firstName ?? "";
|
||||
_txtShippingLastName.text = lastName ?? "";
|
||||
_txtShippingAddressLine.text = addressLine ?? "";
|
||||
_txtShippingCity.text = city ?? "";
|
||||
_txtShippingPostalCode.text = postalCode ?? "";
|
||||
_shippingCountry = customerCountry;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
trans("Billing & Shipping Details"),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: isLoading()
|
||||
? AppLoaderWidget()
|
||||
: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
SwitchAddressTab(
|
||||
title: trans("Billing Details"),
|
||||
currentTabIndex: activeTabIndex,
|
||||
type: "billing",
|
||||
onTapAction: () => setState(() {
|
||||
activeTabIndex = 0;
|
||||
activeTab = tabBillingDetails();
|
||||
})),
|
||||
SwitchAddressTab(
|
||||
title: trans("Shipping Address"),
|
||||
currentTabIndex: activeTabIndex,
|
||||
type: "shipping",
|
||||
onTapAction: () => setState(() {
|
||||
activeTabIndex = 1;
|
||||
activeTab =
|
||||
tabShippingDetails();
|
||||
})),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
height: 60,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ThemeColor.get(context)
|
||||
.backgroundContainer,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? wsBoxShadow()
|
||||
: null,
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.only(left: 8, right: 8, top: 8),
|
||||
margin: EdgeInsets.only(top: 8),
|
||||
child: (activeTab ?? tabBillingDetails())),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 16),
|
||||
height: 160,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
PrimaryButton(
|
||||
title: trans("USE DETAILS"),
|
||||
action: _useDetailsTapped,
|
||||
isLoading: isLocked('update_details'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_useDetailsTapped() async {
|
||||
lockRelease('update_details', perform: () async {
|
||||
// Billing email is required for Stripe
|
||||
String billingEmail = _txtBillingEmailAddress.text;
|
||||
if (billingEmail.isNotEmpty && !validate.isEmail(billingEmail)) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans("Please enter a valid shipping email"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomerAddress userBillingAddress = _setCustomerAddress(
|
||||
firstName: _txtBillingFirstName.text,
|
||||
lastName: _txtBillingLastName.text,
|
||||
addressLine: _txtBillingAddressLine.text,
|
||||
city: _txtBillingCity.text,
|
||||
postalCode: _txtBillingPostalCode.text,
|
||||
phoneNumber: _txtBillingPhoneNumber.text,
|
||||
emailAddress: _txtBillingEmailAddress.text.trim(),
|
||||
customerCountry: _billingCountry,
|
||||
),
|
||||
userShippingAddress = _setCustomerAddress(
|
||||
firstName: _txtShippingFirstName.text,
|
||||
lastName: _txtShippingLastName.text,
|
||||
addressLine: _txtShippingAddressLine.text,
|
||||
city: _txtShippingCity.text,
|
||||
postalCode: _txtShippingPostalCode.text,
|
||||
customerCountry: _shippingCountry,
|
||||
);
|
||||
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
WPUserInfoUpdatedResponse? wpUserInfoUpdatedResponse;
|
||||
try {
|
||||
wpUserInfoUpdatedResponse = await WPJsonAPI.instance.api(
|
||||
(request) => request.wpUpdateUserInfo(userToken, wpUserMetaData: [
|
||||
...userBillingAddress.toUserMetaDataItem('billing'),
|
||||
...userShippingAddress.toUserMetaDataItem('shipping'),
|
||||
]),
|
||||
);
|
||||
} on Exception catch (_) {
|
||||
showToastNotification(context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER);
|
||||
}
|
||||
|
||||
if (wpUserInfoUpdatedResponse != null &&
|
||||
wpUserInfoUpdatedResponse.status == 200) {
|
||||
showToastNotification(context,
|
||||
title: trans("Success"),
|
||||
description: trans("Account updated"),
|
||||
style: ToastNotificationStyleType.SUCCESS);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CustomerAddress _setCustomerAddress(
|
||||
{required String firstName,
|
||||
required String lastName,
|
||||
required String addressLine,
|
||||
required String city,
|
||||
required String postalCode,
|
||||
String? emailAddress,
|
||||
String? phoneNumber,
|
||||
required CustomerCountry? customerCountry}) {
|
||||
CustomerAddress customerShippingAddress = CustomerAddress();
|
||||
customerShippingAddress.firstName = firstName;
|
||||
customerShippingAddress.lastName = lastName;
|
||||
customerShippingAddress.addressLine = addressLine;
|
||||
customerShippingAddress.city = city;
|
||||
customerShippingAddress.postalCode = postalCode;
|
||||
if (phoneNumber != null && phoneNumber != "") {
|
||||
customerShippingAddress.phoneNumber = phoneNumber;
|
||||
}
|
||||
customerShippingAddress.customerCountry = customerCountry;
|
||||
customerShippingAddress.emailAddress = emailAddress;
|
||||
return customerShippingAddress;
|
||||
}
|
||||
|
||||
_navigateToSelectCountry({required String type}) {
|
||||
Navigator.pushNamed(context, "/customer-countries").then((value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == "billing") {
|
||||
_billingCountry = CustomerCountry.fromDefaultShipping(
|
||||
defaultShipping: value as DefaultShipping);
|
||||
activeTab = tabBillingDetails();
|
||||
} else if (type == "shipping") {
|
||||
_shippingCountry = CustomerCountry.fromDefaultShipping(
|
||||
defaultShipping: value as DefaultShipping);
|
||||
activeTab = tabShippingDetails();
|
||||
}
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
_fetchUserDetails() async {
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
WPUserInfoResponse? wpUserInfoResponse;
|
||||
try {
|
||||
wpUserInfoResponse = await WPJsonAPI.instance
|
||||
.api((request) => request.wpGetUserInfo(userToken!));
|
||||
} on Exception catch (e) {
|
||||
print(e.toString());
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
if (wpUserInfoResponse != null && wpUserInfoResponse.status == 200) {
|
||||
BillingDetails billingDetails =
|
||||
await billingDetailsFromWpUserInfoResponse(wpUserInfoResponse);
|
||||
|
||||
_setFieldsFromCustomerAddress(billingDetails.shippingAddress,
|
||||
type: "shipping");
|
||||
_setFieldsFromCustomerAddress(billingDetails.billingAddress,
|
||||
type: "billing");
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -294,7 +294,8 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ?? true) {
|
||||
if (checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ??
|
||||
true) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
@ -1,437 +0,0 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/billing_details.dart';
|
||||
import 'package:flutter_app/app/models/checkout_session.dart';
|
||||
import 'package:flutter_app/app/models/customer_address.dart';
|
||||
import 'package:flutter_app/app/models/customer_country.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/customer_address_input.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/switch_address_tab.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:validated/validated.dart' as validate;
|
||||
|
||||
import '../../app/models/default_shipping.dart';
|
||||
|
||||
class CheckoutDetailsPage extends StatefulWidget {
|
||||
CheckoutDetailsPage();
|
||||
|
||||
@override
|
||||
_CheckoutDetailsPageState createState() => _CheckoutDetailsPageState();
|
||||
}
|
||||
|
||||
class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
|
||||
_CheckoutDetailsPageState();
|
||||
|
||||
bool? _hasDifferentShippingAddress = false, valRememberDetails = true;
|
||||
int activeTabIndex = 0;
|
||||
|
||||
// TEXT CONTROLLERS
|
||||
final TextEditingController
|
||||
// billing
|
||||
_txtBillingFirstName = TextEditingController(),
|
||||
_txtBillingLastName = TextEditingController(),
|
||||
_txtBillingAddressLine = TextEditingController(),
|
||||
_txtBillingCity = TextEditingController(),
|
||||
_txtBillingPostalCode = TextEditingController(),
|
||||
_txtBillingEmailAddress = TextEditingController(),
|
||||
_txtBillingPhoneNumber = TextEditingController(),
|
||||
// shipping
|
||||
_txtShippingFirstName = TextEditingController(),
|
||||
_txtShippingLastName = TextEditingController(),
|
||||
_txtShippingAddressLine = TextEditingController(),
|
||||
_txtShippingCity = TextEditingController(),
|
||||
_txtShippingPostalCode = TextEditingController(),
|
||||
_txtShippingEmailAddress = TextEditingController();
|
||||
|
||||
CustomerCountry? _billingCountry, _shippingCountry;
|
||||
|
||||
Widget? activeTab;
|
||||
|
||||
Widget tabShippingDetails() => CustomerAddressInput(
|
||||
txtControllerFirstName: _txtShippingFirstName,
|
||||
txtControllerLastName: _txtShippingLastName,
|
||||
txtControllerAddressLine: _txtShippingAddressLine,
|
||||
txtControllerCity: _txtShippingCity,
|
||||
txtControllerPostalCode: _txtShippingPostalCode,
|
||||
txtControllerEmailAddress: _txtShippingEmailAddress,
|
||||
customerCountry: _shippingCountry,
|
||||
onTapCountry: () => _navigateToSelectCountry(type: "shipping"),
|
||||
);
|
||||
|
||||
Widget tabBillingDetails() => CustomerAddressInput(
|
||||
txtControllerFirstName: _txtBillingFirstName,
|
||||
txtControllerLastName: _txtBillingLastName,
|
||||
txtControllerAddressLine: _txtBillingAddressLine,
|
||||
txtControllerCity: _txtBillingCity,
|
||||
txtControllerPostalCode: _txtBillingPostalCode,
|
||||
txtControllerEmailAddress: _txtBillingEmailAddress,
|
||||
txtControllerPhoneNumber: _txtBillingPhoneNumber,
|
||||
customerCountry: _billingCountry,
|
||||
onTapCountry: () => _navigateToSelectCountry(type: "billing"),
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
if (CheckoutSession.getInstance.billingDetails!.billingAddress == null) {
|
||||
CheckoutSession.getInstance.billingDetails!.initSession();
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress!
|
||||
.initAddress();
|
||||
CheckoutSession.getInstance.billingDetails!.billingAddress?.initAddress();
|
||||
}
|
||||
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails!;
|
||||
_setFieldsFromCustomerAddress(billingDetails.billingAddress,
|
||||
type: "billing");
|
||||
_setFieldsFromCustomerAddress(billingDetails.shippingAddress,
|
||||
type: "shipping");
|
||||
|
||||
_hasDifferentShippingAddress =
|
||||
CheckoutSession.getInstance.shipToDifferentAddress;
|
||||
valRememberDetails = billingDetails.rememberDetails ?? true;
|
||||
_setCustomersDetails();
|
||||
}
|
||||
|
||||
_setCustomersDetails() async {
|
||||
CustomerAddress? sfCustomerBillingAddress =
|
||||
await CheckoutSession.getInstance.getBillingAddress();
|
||||
_setFieldsFromCustomerAddress(sfCustomerBillingAddress, type: "billing");
|
||||
|
||||
CustomerAddress? sfCustomerShippingAddress =
|
||||
await CheckoutSession.getInstance.getShippingAddress();
|
||||
_setFieldsFromCustomerAddress(sfCustomerShippingAddress, type: "shipping");
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
_setFieldsFromCustomerAddress(CustomerAddress? customerAddress,
|
||||
{required String type}) {
|
||||
assert(type != "");
|
||||
if (customerAddress == null) {
|
||||
return;
|
||||
}
|
||||
_setFields(
|
||||
firstName: customerAddress.firstName,
|
||||
lastName: customerAddress.lastName,
|
||||
addressLine: customerAddress.addressLine,
|
||||
city: customerAddress.city,
|
||||
postalCode: customerAddress.postalCode,
|
||||
emailAddress: customerAddress.emailAddress,
|
||||
phoneNumber: customerAddress.phoneNumber,
|
||||
customerCountry: customerAddress.customerCountry,
|
||||
type: type,
|
||||
);
|
||||
}
|
||||
|
||||
_setFields(
|
||||
{required String? firstName,
|
||||
required String? lastName,
|
||||
required String? addressLine,
|
||||
required String? city,
|
||||
required String? postalCode,
|
||||
required String? emailAddress,
|
||||
required String? phoneNumber,
|
||||
required CustomerCountry? customerCountry,
|
||||
String? type}) {
|
||||
if (type == "billing") {
|
||||
_txtBillingFirstName.text = firstName!;
|
||||
_txtBillingLastName.text = lastName!;
|
||||
_txtBillingAddressLine.text = addressLine!;
|
||||
_txtBillingCity.text = city!;
|
||||
_txtBillingPostalCode.text = postalCode!;
|
||||
_txtBillingPhoneNumber.text = phoneNumber ?? "";
|
||||
_txtBillingEmailAddress.text = emailAddress!;
|
||||
_billingCountry = customerCountry;
|
||||
} else if (type == "shipping") {
|
||||
_txtShippingFirstName.text = firstName!;
|
||||
_txtShippingLastName.text = lastName!;
|
||||
_txtShippingAddressLine.text = addressLine!;
|
||||
_txtShippingCity.text = city!;
|
||||
_txtShippingPostalCode.text = postalCode!;
|
||||
_txtShippingEmailAddress.text = emailAddress!;
|
||||
_shippingCountry = customerCountry;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
trans("Billing & Shipping Details"),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if (_hasDifferentShippingAddress!)
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
SwitchAddressTab(
|
||||
title: trans("Billing Details"),
|
||||
currentTabIndex: activeTabIndex,
|
||||
type: "billing",
|
||||
onTapAction: () => setState(() {
|
||||
activeTabIndex = 0;
|
||||
activeTab = tabBillingDetails();
|
||||
})),
|
||||
SwitchAddressTab(
|
||||
title: trans("Shipping Address"),
|
||||
currentTabIndex: activeTabIndex,
|
||||
type: "shipping",
|
||||
onTapAction: () => setState(() {
|
||||
activeTabIndex = 1;
|
||||
activeTab = tabShippingDetails();
|
||||
})),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
height: 60,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ThemeColor.get(context).backgroundContainer,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? wsBoxShadow()
|
||||
: null,
|
||||
),
|
||||
padding: EdgeInsets.only(left: 8, right: 8, top: 8),
|
||||
margin: EdgeInsets.only(top: 8),
|
||||
child: (activeTab ?? tabBillingDetails())),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 160,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
trans("Ship to a different address?"),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
),
|
||||
Checkbox(
|
||||
value: _hasDifferentShippingAddress,
|
||||
onChanged: _onChangeShipping,
|
||||
)
|
||||
],
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
trans("Remember my details"),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
),
|
||||
Checkbox(
|
||||
value: valRememberDetails,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
valRememberDetails = value;
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
PrimaryButton(
|
||||
title: trans("USE DETAILS"),
|
||||
action: _useDetailsTapped,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_useDetailsTapped() async {
|
||||
CustomerAddress customerBillingAddress = _setCustomerAddress(
|
||||
firstName: _txtBillingFirstName.text,
|
||||
lastName: _txtBillingLastName.text,
|
||||
addressLine: _txtBillingAddressLine.text,
|
||||
city: _txtBillingCity.text,
|
||||
postalCode: _txtBillingPostalCode.text,
|
||||
phoneNumber: _txtBillingPhoneNumber.text,
|
||||
emailAddress: _txtBillingEmailAddress.text.trim(),
|
||||
customerCountry: _billingCountry,
|
||||
);
|
||||
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress =
|
||||
customerBillingAddress;
|
||||
CheckoutSession.getInstance.billingDetails!.billingAddress =
|
||||
customerBillingAddress;
|
||||
|
||||
if (_hasDifferentShippingAddress == true) {
|
||||
CustomerAddress customerShippingAddress = _setCustomerAddress(
|
||||
firstName: _txtShippingFirstName.text,
|
||||
lastName: _txtShippingLastName.text,
|
||||
addressLine: _txtShippingAddressLine.text,
|
||||
city: _txtShippingCity.text,
|
||||
postalCode: _txtShippingPostalCode.text,
|
||||
emailAddress: _txtShippingEmailAddress.text.trim(),
|
||||
customerCountry: _shippingCountry);
|
||||
|
||||
if (customerShippingAddress.hasMissingFields()) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans(
|
||||
"Invalid shipping address, please check your shipping details"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress =
|
||||
customerShippingAddress;
|
||||
}
|
||||
|
||||
// Email validation
|
||||
String billingEmail = CheckoutSession.getInstance.billingDetails!.billingAddress!.emailAddress!;
|
||||
String shippingEmail = CheckoutSession.getInstance.billingDetails!.shippingAddress!.emailAddress!;
|
||||
// Billing email is required for Stripe
|
||||
if (billingEmail.isEmpty || !validate.isEmail(billingEmail)) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans("Please enter a valid billing email"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (shippingEmail.isNotEmpty && !validate.isEmail(shippingEmail)) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans("Please enter a valid shipping email"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (valRememberDetails == true) {
|
||||
await CheckoutSession.getInstance.saveBillingAddress();
|
||||
await CheckoutSession.getInstance.saveShippingAddress();
|
||||
} else {
|
||||
await CheckoutSession.getInstance.clearBillingAddress();
|
||||
await CheckoutSession.getInstance.clearShippingAddress();
|
||||
}
|
||||
|
||||
CheckoutSession.getInstance.billingDetails!.rememberDetails =
|
||||
valRememberDetails;
|
||||
CheckoutSession.getInstance.shipToDifferentAddress =
|
||||
_hasDifferentShippingAddress;
|
||||
|
||||
CheckoutSession.getInstance.shippingType = null;
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
_onChangeShipping(bool? value) async {
|
||||
_hasDifferentShippingAddress = value;
|
||||
activeTabIndex = 1;
|
||||
activeTab = value == true ? tabShippingDetails() : tabBillingDetails();
|
||||
|
||||
CustomerAddress? sfCustomerShippingAddress =
|
||||
await CheckoutSession.getInstance.getShippingAddress();
|
||||
if (sfCustomerShippingAddress == null) {
|
||||
_setFields(
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
addressLine: "",
|
||||
city: "",
|
||||
postalCode: "",
|
||||
phoneNumber: "",
|
||||
emailAddress: "",
|
||||
customerCountry: CustomerCountry());
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
CustomerAddress _setCustomerAddress(
|
||||
{required String firstName,
|
||||
required String lastName,
|
||||
required String addressLine,
|
||||
required String city,
|
||||
required String postalCode,
|
||||
required String emailAddress,
|
||||
String? phoneNumber,
|
||||
required CustomerCountry? customerCountry}) {
|
||||
CustomerAddress customerShippingAddress = CustomerAddress();
|
||||
customerShippingAddress.firstName = firstName;
|
||||
customerShippingAddress.lastName = lastName;
|
||||
customerShippingAddress.addressLine = addressLine;
|
||||
customerShippingAddress.city = city;
|
||||
customerShippingAddress.postalCode = postalCode;
|
||||
if (phoneNumber != null && phoneNumber != "") {
|
||||
customerShippingAddress.phoneNumber = phoneNumber;
|
||||
}
|
||||
customerShippingAddress.customerCountry = customerCountry;
|
||||
customerShippingAddress.emailAddress = emailAddress;
|
||||
return customerShippingAddress;
|
||||
}
|
||||
|
||||
_navigateToSelectCountry({required String type}) {
|
||||
Navigator.pushNamed(context, "/customer-countries").then((value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (type == "billing") {
|
||||
_billingCountry = CustomerCountry.fromDefaultShipping(
|
||||
defaultShipping: value as DefaultShipping);
|
||||
activeTab = tabBillingDetails();
|
||||
} else if (type == "shipping") {
|
||||
_shippingCountry = CustomerCountry.fromDefaultShipping(
|
||||
defaultShipping: value as DefaultShipping);
|
||||
activeTab = tabShippingDetails();
|
||||
}
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
}
|
||||
527
LabelStoreMax/lib/resources/pages/checkout_details_page.dart
Normal file
527
LabelStoreMax/lib/resources/pages/checkout_details_page.dart
Normal file
@ -0,0 +1,527 @@
|
||||
// Label StoreMax
|
||||
//
|
||||
// Created by Anthony Gordon.
|
||||
// 2022, WooSignal Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/billing_details.dart';
|
||||
import 'package:flutter_app/app/models/checkout_session.dart';
|
||||
import 'package:flutter_app/app/models/customer_address.dart';
|
||||
import 'package:flutter_app/app/models/customer_country.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/buttons.dart';
|
||||
import 'package:flutter_app/resources/widgets/customer_address_input.dart';
|
||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/switch_address_tab.dart';
|
||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||
import 'package:nylo_framework/nylo_framework.dart';
|
||||
import 'package:validated/validated.dart' as validate;
|
||||
import 'package:wp_json_api/models/responses/wp_user_info_response.dart';
|
||||
import 'package:wp_json_api/wp_json_api.dart';
|
||||
import '../../app/models/default_shipping.dart';
|
||||
|
||||
class CheckoutDetailsPage extends StatefulWidget {
|
||||
CheckoutDetailsPage();
|
||||
|
||||
@override
|
||||
_CheckoutDetailsPageState createState() => _CheckoutDetailsPageState();
|
||||
}
|
||||
|
||||
class _CheckoutDetailsPageState extends NyState<CheckoutDetailsPage> {
|
||||
_CheckoutDetailsPageState();
|
||||
|
||||
bool? _hasDifferentShippingAddress = false,
|
||||
valRememberDetails = true,
|
||||
_wpLoginEnabled;
|
||||
int activeTabIndex = 0;
|
||||
|
||||
// TEXT CONTROLLERS
|
||||
final TextEditingController
|
||||
// billing
|
||||
_txtBillingFirstName = TextEditingController(),
|
||||
_txtBillingLastName = TextEditingController(),
|
||||
_txtBillingAddressLine = TextEditingController(),
|
||||
_txtBillingCity = TextEditingController(),
|
||||
_txtBillingPostalCode = TextEditingController(),
|
||||
_txtBillingEmailAddress = TextEditingController(),
|
||||
_txtBillingPhoneNumber = TextEditingController(),
|
||||
// shipping
|
||||
_txtShippingFirstName = TextEditingController(),
|
||||
_txtShippingLastName = TextEditingController(),
|
||||
_txtShippingAddressLine = TextEditingController(),
|
||||
_txtShippingCity = TextEditingController(),
|
||||
_txtShippingPostalCode = TextEditingController(),
|
||||
_txtShippingEmailAddress = TextEditingController();
|
||||
|
||||
CustomerCountry? _billingCountry, _shippingCountry;
|
||||
|
||||
Widget? activeTab;
|
||||
|
||||
Widget tabShippingDetails() => CustomerAddressInput(
|
||||
txtControllerFirstName: _txtShippingFirstName,
|
||||
txtControllerLastName: _txtShippingLastName,
|
||||
txtControllerAddressLine: _txtShippingAddressLine,
|
||||
txtControllerCity: _txtShippingCity,
|
||||
txtControllerPostalCode: _txtShippingPostalCode,
|
||||
txtControllerEmailAddress: _txtShippingEmailAddress,
|
||||
customerCountry: _shippingCountry,
|
||||
onTapCountry: () => _navigateToSelectCountry(type: "shipping"),
|
||||
);
|
||||
|
||||
Widget tabBillingDetails() => CustomerAddressInput(
|
||||
txtControllerFirstName: _txtBillingFirstName,
|
||||
txtControllerLastName: _txtBillingLastName,
|
||||
txtControllerAddressLine: _txtBillingAddressLine,
|
||||
txtControllerCity: _txtBillingCity,
|
||||
txtControllerPostalCode: _txtBillingPostalCode,
|
||||
txtControllerEmailAddress: _txtBillingEmailAddress,
|
||||
txtControllerPhoneNumber: _txtBillingPhoneNumber,
|
||||
customerCountry: _billingCountry,
|
||||
onTapCountry: () => _navigateToSelectCountry(type: "billing"),
|
||||
);
|
||||
|
||||
@override
|
||||
void init() async {
|
||||
super.init();
|
||||
|
||||
_wpLoginEnabled = AppHelper.instance.appConfig?.wpLoginEnabled == 1;
|
||||
|
||||
if (_wpLoginEnabled == true) {
|
||||
await awaitData(perform: () async {
|
||||
await _fetchUserDetails();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckoutSession.getInstance.billingDetails!.billingAddress == null) {
|
||||
CheckoutSession.getInstance.billingDetails!.initSession();
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress!
|
||||
.initAddress();
|
||||
CheckoutSession.getInstance.billingDetails!.billingAddress?.initAddress();
|
||||
}
|
||||
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails!;
|
||||
_setFieldsFromCustomerAddress(billingDetails.billingAddress,
|
||||
type: "billing");
|
||||
_setFieldsFromCustomerAddress(billingDetails.shippingAddress,
|
||||
type: "shipping");
|
||||
|
||||
_hasDifferentShippingAddress =
|
||||
CheckoutSession.getInstance.shipToDifferentAddress;
|
||||
valRememberDetails = billingDetails.rememberDetails ?? true;
|
||||
if (valRememberDetails == true) {
|
||||
await _setCustomersDetailsFromRemember();
|
||||
return;
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
_setCustomersDetailsFromRemember() async {
|
||||
CustomerAddress? sfCustomerBillingAddress =
|
||||
await CheckoutSession.getInstance.getBillingAddress();
|
||||
_setFieldsFromCustomerAddress(sfCustomerBillingAddress, type: "billing");
|
||||
|
||||
CustomerAddress? sfCustomerShippingAddress =
|
||||
await CheckoutSession.getInstance.getShippingAddress();
|
||||
_setFieldsFromCustomerAddress(sfCustomerShippingAddress, type: "shipping");
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
_setFieldsFromCustomerAddress(CustomerAddress? customerAddress,
|
||||
{required String type}) {
|
||||
assert(type != "");
|
||||
if (customerAddress == null) {
|
||||
return;
|
||||
}
|
||||
_setFields(
|
||||
firstName: customerAddress.firstName,
|
||||
lastName: customerAddress.lastName,
|
||||
addressLine: customerAddress.addressLine,
|
||||
city: customerAddress.city,
|
||||
postalCode: customerAddress.postalCode,
|
||||
emailAddress: customerAddress.emailAddress,
|
||||
phoneNumber: customerAddress.phoneNumber,
|
||||
customerCountry: customerAddress.customerCountry,
|
||||
type: type,
|
||||
);
|
||||
}
|
||||
|
||||
_setFields(
|
||||
{required String? firstName,
|
||||
required String? lastName,
|
||||
required String? addressLine,
|
||||
required String? city,
|
||||
required String? postalCode,
|
||||
required String? emailAddress,
|
||||
required String? phoneNumber,
|
||||
required CustomerCountry? customerCountry,
|
||||
String? type}) {
|
||||
if (type == "billing") {
|
||||
_txtBillingFirstName.text = firstName ?? "";
|
||||
_txtBillingLastName.text = lastName ?? "";
|
||||
_txtBillingAddressLine.text = addressLine ?? "";
|
||||
_txtBillingCity.text = city ?? "";
|
||||
_txtBillingPostalCode.text = postalCode ?? "";
|
||||
_txtBillingPhoneNumber.text = phoneNumber ?? "";
|
||||
_txtBillingEmailAddress.text = emailAddress ?? "";
|
||||
_billingCountry = customerCountry;
|
||||
} else if (type == "shipping") {
|
||||
_txtShippingFirstName.text = firstName ?? "";
|
||||
_txtShippingLastName.text = lastName ?? "";
|
||||
_txtShippingAddressLine.text = addressLine ?? "";
|
||||
_txtShippingCity.text = city ?? "";
|
||||
_txtShippingPostalCode.text = postalCode ?? "";
|
||||
_txtShippingEmailAddress.text = emailAddress ?? "";
|
||||
_shippingCountry = customerCountry;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
trans("Billing & Shipping Details"),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: SafeAreaWidget(
|
||||
child: (isLoading() || isLocked('load_shipping_info'))
|
||||
? AppLoaderWidget()
|
||||
: GestureDetector(
|
||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
if (_hasDifferentShippingAddress!)
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(vertical: 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
SwitchAddressTab(
|
||||
title: trans("Billing Details"),
|
||||
currentTabIndex: activeTabIndex,
|
||||
type: "billing",
|
||||
onTapAction: () => setState(() {
|
||||
activeTabIndex = 0;
|
||||
activeTab =
|
||||
tabBillingDetails();
|
||||
})),
|
||||
SwitchAddressTab(
|
||||
title: trans("Shipping Address"),
|
||||
currentTabIndex: activeTabIndex,
|
||||
type: "shipping",
|
||||
onTapAction: () => setState(() {
|
||||
activeTabIndex = 1;
|
||||
activeTab =
|
||||
tabShippingDetails();
|
||||
})),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
height: 60,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ThemeColor.get(context)
|
||||
.backgroundContainer,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
boxShadow: (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? wsBoxShadow()
|
||||
: null,
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.only(left: 8, right: 8, top: 8),
|
||||
margin: EdgeInsets.only(top: 8),
|
||||
child: (activeTab ?? tabBillingDetails())),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 160,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
trans("Ship to a different address?"),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
),
|
||||
Checkbox(
|
||||
value: _hasDifferentShippingAddress,
|
||||
onChanged: _onChangeShipping,
|
||||
)
|
||||
],
|
||||
),
|
||||
if (_wpLoginEnabled == true)
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
trans("Remember my details"),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
),
|
||||
Checkbox(
|
||||
value: valRememberDetails,
|
||||
onChanged: (bool? value) {
|
||||
setState(() {
|
||||
valRememberDetails = value;
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
PrimaryButton(
|
||||
title: trans("USE DETAILS"),
|
||||
action: _useDetailsTapped,
|
||||
isLoading: isLocked('update_shipping'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_useDetailsTapped() async {
|
||||
await lockRelease('update_shipping', perform: () async {
|
||||
CustomerAddress customerBillingAddress = _setCustomerAddress(
|
||||
firstName: _txtBillingFirstName.text,
|
||||
lastName: _txtBillingLastName.text,
|
||||
addressLine: _txtBillingAddressLine.text,
|
||||
city: _txtBillingCity.text,
|
||||
postalCode: _txtBillingPostalCode.text,
|
||||
phoneNumber: _txtBillingPhoneNumber.text,
|
||||
emailAddress: _txtBillingEmailAddress.text.trim(),
|
||||
customerCountry: _billingCountry,
|
||||
);
|
||||
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress =
|
||||
customerBillingAddress;
|
||||
CheckoutSession.getInstance.billingDetails!.billingAddress =
|
||||
customerBillingAddress;
|
||||
|
||||
if (_hasDifferentShippingAddress == true) {
|
||||
CustomerAddress customerShippingAddress = _setCustomerAddress(
|
||||
firstName: _txtShippingFirstName.text,
|
||||
lastName: _txtShippingLastName.text,
|
||||
addressLine: _txtShippingAddressLine.text,
|
||||
city: _txtShippingCity.text,
|
||||
postalCode: _txtShippingPostalCode.text,
|
||||
emailAddress: _txtShippingEmailAddress.text.trim(),
|
||||
customerCountry: _shippingCountry);
|
||||
|
||||
if (customerShippingAddress.hasMissingFields()) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans(
|
||||
"Invalid shipping address, please check your shipping details"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
CheckoutSession.getInstance.billingDetails!.shippingAddress =
|
||||
customerShippingAddress;
|
||||
}
|
||||
|
||||
BillingDetails billingDetails =
|
||||
CheckoutSession.getInstance.billingDetails!;
|
||||
|
||||
// Email validation
|
||||
String billingEmail = billingDetails.billingAddress!.emailAddress!;
|
||||
String shippingEmail = billingDetails.shippingAddress!.emailAddress!;
|
||||
// Billing email is required for Stripe
|
||||
if (billingEmail.isEmpty || !validate.isEmail(billingEmail)) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans("Please enter a valid billing email"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (shippingEmail.isNotEmpty && !validate.isEmail(shippingEmail)) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
description: trans("Please enter a valid shipping email"),
|
||||
style: ToastNotificationStyleType.WARNING,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update WP shipping info for user
|
||||
if (_wpLoginEnabled == true) {
|
||||
String? userToken = await readAuthToken();
|
||||
|
||||
try {
|
||||
await WPJsonAPI.instance.api(
|
||||
(request) => request.wpUpdateUserInfo(userToken, wpUserMetaData: [
|
||||
...?billingDetails.billingAddress?.toUserMetaDataItem('billing'),
|
||||
...?billingDetails.shippingAddress
|
||||
?.toUserMetaDataItem('shipping'),
|
||||
]),
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
showToastNotification(context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER);
|
||||
if (getEnv('APP_DEBUG', defaultValue: true) == true) {
|
||||
NyLogger.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valRememberDetails == true) {
|
||||
await CheckoutSession.getInstance.saveBillingAddress();
|
||||
await CheckoutSession.getInstance.saveShippingAddress();
|
||||
} else {
|
||||
await CheckoutSession.getInstance.clearBillingAddress();
|
||||
await CheckoutSession.getInstance.clearShippingAddress();
|
||||
}
|
||||
|
||||
CheckoutSession.getInstance.billingDetails!.rememberDetails =
|
||||
valRememberDetails;
|
||||
CheckoutSession.getInstance.shipToDifferentAddress =
|
||||
_hasDifferentShippingAddress;
|
||||
|
||||
CheckoutSession.getInstance.shippingType = null;
|
||||
Navigator.pop(context);
|
||||
});
|
||||
}
|
||||
|
||||
_onChangeShipping(bool? value) async {
|
||||
_hasDifferentShippingAddress = value;
|
||||
activeTabIndex = 1;
|
||||
activeTab = value == true ? tabShippingDetails() : tabBillingDetails();
|
||||
|
||||
CustomerAddress? sfCustomerShippingAddress =
|
||||
await CheckoutSession.getInstance.getShippingAddress();
|
||||
if (sfCustomerShippingAddress == null) {
|
||||
_setFields(
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
addressLine: "",
|
||||
city: "",
|
||||
postalCode: "",
|
||||
phoneNumber: "",
|
||||
emailAddress: "",
|
||||
customerCountry: CustomerCountry());
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
CustomerAddress _setCustomerAddress(
|
||||
{required String firstName,
|
||||
required String lastName,
|
||||
required String addressLine,
|
||||
required String city,
|
||||
required String postalCode,
|
||||
required String emailAddress,
|
||||
String? phoneNumber,
|
||||
required CustomerCountry? customerCountry}) {
|
||||
CustomerAddress customerShippingAddress = CustomerAddress();
|
||||
customerShippingAddress.firstName = firstName;
|
||||
customerShippingAddress.lastName = lastName;
|
||||
customerShippingAddress.addressLine = addressLine;
|
||||
customerShippingAddress.city = city;
|
||||
customerShippingAddress.postalCode = postalCode;
|
||||
if (phoneNumber != null && phoneNumber != "") {
|
||||
customerShippingAddress.phoneNumber = phoneNumber;
|
||||
}
|
||||
customerShippingAddress.customerCountry = customerCountry;
|
||||
customerShippingAddress.emailAddress = emailAddress;
|
||||
return customerShippingAddress;
|
||||
}
|
||||
|
||||
_navigateToSelectCountry({required String type}) {
|
||||
Navigator.pushNamed(context, "/customer-countries").then((value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (type == "billing") {
|
||||
_billingCountry = CustomerCountry.fromDefaultShipping(
|
||||
defaultShipping: value as DefaultShipping);
|
||||
activeTab = tabBillingDetails();
|
||||
} else if (type == "shipping") {
|
||||
_shippingCountry = CustomerCountry.fromDefaultShipping(
|
||||
defaultShipping: value as DefaultShipping);
|
||||
activeTab = tabShippingDetails();
|
||||
}
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
_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!));
|
||||
} on Exception catch (e) {
|
||||
print(e.toString());
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops!"),
|
||||
description: trans("Something went wrong"),
|
||||
style: ToastNotificationStyleType.DANGER,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
if (wpUserInfoResponse != null && wpUserInfoResponse.status == 200) {
|
||||
BillingDetails billingDetails =
|
||||
await billingDetailsFromWpUserInfoResponse(wpUserInfoResponse);
|
||||
|
||||
_setFieldsFromCustomerAddress(billingDetails.shippingAddress,
|
||||
type: "shipping");
|
||||
_setFieldsFromCustomerAddress(billingDetails.billingAddress,
|
||||
type: "billing");
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -330,9 +330,8 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
|
||||
"min_amount"] !=
|
||||
null)
|
||||
TextSpan(
|
||||
text: "\n${trans("Spend a minimum of")} ${formatStringCurrency(
|
||||
total: shippingOption[
|
||||
"min_amount"])}",
|
||||
text:
|
||||
"\n${trans("Spend a minimum of")} ${formatStringCurrency(total: shippingOption["min_amount"])}",
|
||||
style: Theme.of(
|
||||
context)
|
||||
.textTheme
|
||||
@ -366,7 +365,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
|
||||
)
|
||||
: Text(
|
||||
trans(
|
||||
"Shipping is not supported for your country, sorry"),
|
||||
"Shipping is not supported for your location, sorry"),
|
||||
style:
|
||||
Theme.of(context).textTheme.headline6,
|
||||
textAlign: TextAlign.center,
|
||||
@ -35,7 +35,7 @@ class _CustomerCountriesPageState extends State<CustomerCountriesPage> {
|
||||
}
|
||||
|
||||
_getDefaultShipping() async {
|
||||
_defaultShipping = await getDefaultShipping(context);
|
||||
_defaultShipping = await getDefaultShipping();
|
||||
_activeShippingResults = _defaultShipping;
|
||||
setState(() {});
|
||||
}
|
||||
@ -33,25 +33,16 @@ class AccountDetailSettingsWidget extends StatelessWidget {
|
||||
Card(
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.local_shipping),
|
||||
title: Text(trans("Shipping Details")),
|
||||
title: Text(trans("Billing/shipping details")),
|
||||
onTap: () =>
|
||||
Navigator.pushNamed(context, "/account-shipping-details"),
|
||||
),
|
||||
),
|
||||
Card(
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.credit_card),
|
||||
title: Text(trans("Billing Details")),
|
||||
onTap: () =>
|
||||
Navigator.pushNamed(context, "/account-billing-details"),
|
||||
),
|
||||
),
|
||||
Card(
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.no_accounts_rounded),
|
||||
title: Text(trans("Delete Account")),
|
||||
onTap: () =>
|
||||
Navigator.pushNamed(context, "/account-delete"),
|
||||
onTap: () => Navigator.pushNamed(context, "/account-delete"),
|
||||
),
|
||||
),
|
||||
Card(
|
||||
|
||||
@ -63,7 +63,8 @@ class CheckoutSelectCouponWidget extends StatelessWidget {
|
||||
|
||||
return;
|
||||
}
|
||||
if (checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ?? true) {
|
||||
if (checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ??
|
||||
true) {
|
||||
showToastNotification(
|
||||
context,
|
||||
title: trans("Oops"),
|
||||
|
||||
@ -7,18 +7,18 @@ class CheckoutStoreHeadingWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: (Theme.of(context).brightness == Brightness.light)
|
||||
? wsBoxShadow(blurRadius: 10)
|
||||
: null,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
padding: EdgeInsets.all(2),
|
||||
margin: EdgeInsets.only(top: 16),
|
||||
child: ClipRRect(
|
||||
child: StoreLogo(height: 65),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
boxShadow: (Theme.of(context).brightness == Brightness.light)
|
||||
? wsBoxShadow(blurRadius: 10)
|
||||
: null,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
padding: EdgeInsets.all(2),
|
||||
margin: EdgeInsets.only(top: 16),
|
||||
child: ClipRRect(
|
||||
child: StoreLogo(height: 65),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ class CheckoutUserDetailsWidget extends StatelessWidget {
|
||||
leadImage: Icon(Icons.home),
|
||||
leadTitle: hasUserCheckoutInfo
|
||||
? (checkoutSession.billingDetails == null ||
|
||||
(checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ?? true)
|
||||
(checkoutSession.billingDetails?.billingAddress
|
||||
?.hasMissingFields() ??
|
||||
true)
|
||||
? trans("Billing address is incomplete")
|
||||
: checkoutSession.billingDetails!.billingAddress?.addressFull())
|
||||
: trans("Add billing & shipping details"),
|
||||
|
||||
@ -15,11 +15,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/bottom_nav_item.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/pages/account_detail.dart';
|
||||
import 'package:flutter_app/resources/pages/account_landing.dart';
|
||||
import 'package:flutter_app/resources/pages/cart.dart';
|
||||
import 'package:flutter_app/resources/pages/account_detail_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_landing_page.dart';
|
||||
import 'package:flutter_app/resources/pages/cart_page.dart';
|
||||
import 'package:flutter_app/resources/pages/wishlist_page_widget.dart';
|
||||
import 'package:flutter_app/resources/pages/home_search.dart';
|
||||
import 'package:flutter_app/resources/pages/home_search_page.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/compo_home_widget.dart';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
|
||||
@ -22,7 +22,7 @@ class CustomerAddressInput extends StatelessWidget {
|
||||
required this.txtControllerAddressLine,
|
||||
required this.txtControllerCity,
|
||||
required this.txtControllerPostalCode,
|
||||
required this.txtControllerEmailAddress,
|
||||
this.txtControllerEmailAddress,
|
||||
this.txtControllerPhoneNumber,
|
||||
required this.customerCountry,
|
||||
required this.onTapCountry})
|
||||
@ -87,12 +87,13 @@ class CustomerAddressInput extends StatelessWidget {
|
||||
controller: txtControllerPostalCode,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Email address"),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: txtControllerEmailAddress),
|
||||
),
|
||||
if (txtControllerEmailAddress == null)
|
||||
Flexible(
|
||||
child: TextEditingRow(
|
||||
heading: trans("Email address"),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
controller: txtControllerEmailAddress),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (txtControllerPhoneNumber != null)
|
||||
@ -111,7 +112,7 @@ class CustomerAddressInput extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
if (customerCountry!.hasState())
|
||||
if (customerCountry?.hasState() ?? false)
|
||||
Flexible(
|
||||
child: Column(
|
||||
children: [
|
||||
|
||||
@ -13,9 +13,11 @@ import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_version_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
|
||||
import 'package:flutter_app/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';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@ -30,13 +32,13 @@ class HomeDrawerWidget extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _HomeDrawerWidgetState extends State<HomeDrawerWidget> {
|
||||
Map<String, dynamic> _socialLinks = {};
|
||||
List<MenuLink> _menuLinks = [];
|
||||
String? _themeType;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_socialLinks = AppHelper.instance.appConfig!.socialLinks ?? {};
|
||||
_menuLinks = AppHelper.instance.appConfig?.menuLinks ?? [];
|
||||
_themeType = AppHelper.instance.appConfig!.theme;
|
||||
}
|
||||
|
||||
@ -157,7 +159,7 @@ class _HomeDrawerWidgetState extends State<HomeDrawerWidget> {
|
||||
});
|
||||
},
|
||||
),
|
||||
if (_socialLinks.isNotEmpty)
|
||||
if (_menuLinks.isNotEmpty)
|
||||
Padding(
|
||||
child: Text(
|
||||
trans("Social"),
|
||||
@ -165,20 +167,23 @@ class _HomeDrawerWidgetState extends State<HomeDrawerWidget> {
|
||||
),
|
||||
padding: EdgeInsets.only(left: 16, top: 8, bottom: 8),
|
||||
),
|
||||
..._socialLinks.entries
|
||||
.where((element) => element.value != "")
|
||||
.map((socialLink) => ListTile(
|
||||
title: Text(capitalize(socialLink.key),
|
||||
..._menuLinks
|
||||
.where((element) => element.label != "")
|
||||
.map((menuLink) => ListTile(
|
||||
title: Text(menuLink.label,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText2!
|
||||
.copyWith(fontSize: 16)),
|
||||
leading: Image.asset(
|
||||
'${getImageAsset(socialLink.key)}.png',
|
||||
height: 25,
|
||||
width: 25),
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
child: CachedImageWidget(
|
||||
image: menuLink.iconUrl,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
onTap: () async =>
|
||||
await launchUrl(Uri.parse(socialLink.value)),
|
||||
await launchUrl(Uri.parse(menuLink.linkUrl)),
|
||||
))
|
||||
.toList(),
|
||||
ListTile(
|
||||
@ -213,6 +218,4 @@ class _HomeDrawerWidgetState extends State<HomeDrawerWidget> {
|
||||
Navigator.pop(context);
|
||||
Navigator.pushNamed(context, "/cart");
|
||||
}
|
||||
|
||||
String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
||||
@ -15,11 +15,11 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/app/models/bottom_nav_item.dart';
|
||||
import 'package:flutter_app/bootstrap/app_helper.dart';
|
||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||
import 'package:flutter_app/resources/pages/account_detail.dart';
|
||||
import 'package:flutter_app/resources/pages/account_landing.dart';
|
||||
import 'package:flutter_app/resources/pages/cart.dart';
|
||||
import 'package:flutter_app/resources/pages/account_detail_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_landing_page.dart';
|
||||
import 'package:flutter_app/resources/pages/cart_page.dart';
|
||||
import 'package:flutter_app/resources/pages/wishlist_page_widget.dart';
|
||||
import 'package:flutter_app/resources/pages/home_search.dart';
|
||||
import 'package:flutter_app/resources/pages/home_search_page.dart';
|
||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||
import 'package:flutter_app/resources/widgets/notic_home_widget.dart';
|
||||
import 'package:woosignal/models/response/woosignal_app.dart';
|
||||
|
||||
@ -1,26 +1,25 @@
|
||||
import 'package:flutter_app/resources/pages/account_billing_details.dart';
|
||||
import 'package:flutter_app/resources/pages/account_delete_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_detail.dart';
|
||||
import 'package:flutter_app/resources/pages/account_landing.dart';
|
||||
import 'package:flutter_app/resources/pages/account_order_detail.dart';
|
||||
import 'package:flutter_app/resources/pages/account_profile_update.dart';
|
||||
import 'package:flutter_app/resources/pages/account_register.dart';
|
||||
import 'package:flutter_app/resources/pages/account_shipping_details.dart';
|
||||
import 'package:flutter_app/resources/pages/browse_category.dart';
|
||||
import 'package:flutter_app/resources/pages/browse_search.dart';
|
||||
import 'package:flutter_app/resources/pages/cart.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_details.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_payment_type.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_shipping_type.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_status.dart';
|
||||
import 'package:flutter_app/resources/pages/account_detail_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_landing_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_order_detail_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_profile_update_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_register_page.dart';
|
||||
import 'package:flutter_app/resources/pages/account_shipping_details_page.dart';
|
||||
import 'package:flutter_app/resources/pages/browse_category_page.dart';
|
||||
import 'package:flutter_app/resources/pages/browse_search_page.dart';
|
||||
import 'package:flutter_app/resources/pages/cart_page.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_details_page.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_payment_type_page.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_shipping_type_page.dart';
|
||||
import 'package:flutter_app/resources/pages/checkout_status_page.dart';
|
||||
import 'package:flutter_app/resources/pages/coupon_page.dart';
|
||||
import 'package:flutter_app/resources/pages/customer_countries.dart';
|
||||
import 'package:flutter_app/resources/pages/home.dart';
|
||||
import 'package:flutter_app/resources/pages/home_search.dart';
|
||||
import 'package:flutter_app/resources/pages/customer_countries_page.dart';
|
||||
import 'package:flutter_app/resources/pages/home_page.dart';
|
||||
import 'package:flutter_app/resources/pages/home_search_page.dart';
|
||||
import 'package:flutter_app/resources/pages/leave_review_page.dart';
|
||||
import 'package:flutter_app/resources/pages/no_connection_page.dart';
|
||||
import 'package:flutter_app/resources/pages/product_detail.dart';
|
||||
import 'package:flutter_app/resources/pages/product_detail_page.dart';
|
||||
import 'package:flutter_app/resources/pages/product_image_viewer_page.dart';
|
||||
import 'package:flutter_app/resources/pages/product_reviews_page.dart';
|
||||
import 'package:flutter_app/resources/pages/wishlist_page_widget.dart';
|
||||
@ -105,9 +104,6 @@ appRouter() => nyRoutes((router) {
|
||||
|
||||
router.route("/account-delete", (context) => AccountDeletePage());
|
||||
|
||||
router.route(
|
||||
"/account-billing-details", (context) => AccountBillingDetailsPage());
|
||||
|
||||
router.route("/account-shipping-details",
|
||||
(context) => AccountShippingDetailsPage());
|
||||
});
|
||||
|
||||
@ -8,6 +8,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "41.0.0"
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
analyzer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -120,6 +127,20 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
cloud_firestore_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cloud_firestore_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.8.3"
|
||||
cloud_firestore_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cloud_firestore_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
collection:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -161,42 +182,14 @@ packages:
|
||||
name: device_info_plus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
device_info_plus_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
device_info_plus_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "8.0.0"
|
||||
device_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
device_info_plus_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
device_info_plus_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: device_info_plus_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "7.0.0"
|
||||
dio:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -232,6 +225,48 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.5.2"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "14.0.3"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.4"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.2.4"
|
||||
flare_flutter:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -346,7 +381,7 @@ packages:
|
||||
name: flutter_stripe
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
flutter_styled_toast:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -384,7 +419,7 @@ packages:
|
||||
name: flutter_widget_from_html_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.8.5+3"
|
||||
version: "0.9.0"
|
||||
fluttertoast:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -426,7 +461,7 @@ packages:
|
||||
name: html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.15.0"
|
||||
version: "0.15.1"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -685,7 +720,7 @@ packages:
|
||||
name: plugin_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.3"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -713,7 +748,7 @@ packages:
|
||||
name: razorpay_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.4"
|
||||
recase:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -823,7 +858,7 @@ packages:
|
||||
name: status_alert
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -844,21 +879,21 @@ packages:
|
||||
name: stripe_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
stripe_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stripe_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
stripe_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stripe_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -900,7 +935,7 @@ packages:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
version: "6.1.6"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1016,10 +1051,10 @@ packages:
|
||||
woosignal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: woosignal
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
path: "/Users/anthony/AndroidStudioProjects/woosignal-woocommerce-api"
|
||||
relative: false
|
||||
source: path
|
||||
version: "3.2.0"
|
||||
wp_json_api:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Official WooSignal App Template for WooCommerce
|
||||
|
||||
# Label StoreMax
|
||||
# Version: 6.2.0
|
||||
# Version: 6.3.0
|
||||
# Author: Anthony Gordon
|
||||
# Homepage: https://woosignal.com
|
||||
# Documentation: https://woosignal.com/docs/app/label-storemax
|
||||
@ -29,8 +29,8 @@ dependencies:
|
||||
analyzer: ^4.2.0
|
||||
intl: ^0.17.0
|
||||
nylo_framework: ^3.4.0
|
||||
woosignal: ^3.1.1
|
||||
flutter_stripe: ^5.0.0
|
||||
woosignal: ^3.2.0
|
||||
flutter_stripe: ^6.0.0
|
||||
wp_json_api: ^3.2.0
|
||||
cached_network_image: ^3.2.2
|
||||
package_info: ^2.0.2
|
||||
@ -38,23 +38,23 @@ dependencies:
|
||||
flutter_web_browser: ^0.17.1
|
||||
webview_flutter: ^3.0.4
|
||||
pull_to_refresh_flutter3: 2.0.1
|
||||
url_launcher: ^6.1.5
|
||||
url_launcher: ^6.1.6
|
||||
flutter_styled_toast: ^2.1.3
|
||||
animate_do: ^2.1.0
|
||||
bubble_tab_indicator: ^0.1.5
|
||||
razorpay_flutter: ^1.3.2
|
||||
status_alert: ^1.0.0
|
||||
razorpay_flutter: ^1.3.4
|
||||
status_alert: ^1.0.1
|
||||
math_expressions: ^2.3.1
|
||||
validated: ^2.0.0
|
||||
flutter_spinkit: ^5.1.0
|
||||
auto_size_text: ^3.0.0
|
||||
html: ^0.15.0
|
||||
flutter_widget_from_html_core: ^0.8.5+3
|
||||
html: ^0.15.1
|
||||
flutter_widget_from_html_core: ^0.9.0
|
||||
flutter_rating_bar: ^4.0.1
|
||||
flutter_staggered_grid_view: ^0.6.2
|
||||
flutter_swiper_view: ^1.1.8
|
||||
# firebase_messaging: ^11.2.3
|
||||
# firebase_core: ^1.10.5
|
||||
firebase_messaging: ^14.0.3
|
||||
firebase_core: ^2.1.1
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
@ -63,7 +63,7 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.5
|
||||
collection: ^1.15.0-nullsafety.4
|
||||
collection: ^1.15.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_launcher_icons: ^0.10.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user