flutter-woocommerce-app/LabelStoreMax/lib/resources/pages/checkout_confirmation_page.dart
2023-07-03 07:46:19 +01:00

450 lines
16 KiB
Dart

// Label StoreMax
//
// Created by Anthony Gordon.
// 2023, WooSignal Ltd. All rights reserved.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/app/models/customer_country.dart';
import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.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/checkout_coupon_amount_widget.dart';
import 'package:flutter_app/resources/widgets/checkout_payment_type_widget.dart';
import 'package:flutter_app/resources/widgets/checkout_select_coupon_widget.dart';
import 'package:flutter_app/resources/widgets/checkout_shipping_type_widget.dart';
import 'package:flutter_app/resources/widgets/checkout_store_heading_widget.dart';
import 'package:flutter_app/resources/widgets/checkout_user_details_widget.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:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
class CheckoutConfirmationPage extends StatefulWidget {
CheckoutConfirmationPage({Key? key}) : super(key: key);
@override
CheckoutConfirmationPageState createState() =>
CheckoutConfirmationPageState();
}
class CheckoutConfirmationPageState extends NyState<CheckoutConfirmationPage> {
CheckoutConfirmationPageState();
bool _showFullLoader = true, _isProcessingPayment = false;
final List<TaxRate> _taxRates = [];
TaxRate? _taxRate;
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
@override
init() async {
super.init();
CheckoutSession.getInstance.coupon = null;
List<PaymentType?> paymentTypes = await getPaymentTypes();
if (CheckoutSession.getInstance.paymentType == null &&
paymentTypes.isNotEmpty) {
CheckoutSession.getInstance.paymentType = paymentTypes.firstWhere(
(paymentType) => paymentType?.id == 20,
orElse: () => paymentTypes.first);
}
_getTaxes();
}
reloadState({required bool showLoader}) {
setState(() {
_showFullLoader = showLoader;
});
}
_getTaxes() async {
int pageIndex = 1;
bool fetchMore = true;
while (fetchMore == true) {
List<TaxRate> tmpTaxRates = await (appWooSignal(
(api) => api.getTaxRates(page: pageIndex, perPage: 100)));
if (tmpTaxRates.isNotEmpty) {
_taxRates.addAll(tmpTaxRates);
}
if (tmpTaxRates.length >= 100) {
pageIndex += 1;
} else {
fetchMore = false;
}
}
if (_taxRates.isEmpty) {
setState(() {
_showFullLoader = false;
});
return;
}
if (CheckoutSession.getInstance.billingDetails == null ||
CheckoutSession.getInstance.billingDetails!.shippingAddress == null) {
setState(() {
_showFullLoader = false;
});
return;
}
CustomerCountry? shippingCountry = CheckoutSession
.getInstance.billingDetails!.shippingAddress!.customerCountry;
String? postalCode =
CheckoutSession.getInstance.billingDetails!.shippingAddress!.postalCode;
if (shippingCountry == null) {
_showFullLoader = false;
setState(() {});
return;
}
TaxRate? taxRate;
if (shippingCountry.hasState()) {
taxRate = _taxRates.firstWhereOrNull((t) {
if ((shippingCountry.state?.code ?? "") == "") {
return false;
}
List<String> stateElements = shippingCountry.state!.code!.split(":");
String state = stateElements.last;
if (t.country == shippingCountry.countryCode &&
t.state == state &&
t.postcode == postalCode) {
return true;
}
if (t.country == shippingCountry.countryCode && t.state == state) {
return true;
}
return false;
});
}
if (taxRate == null) {
taxRate = _taxRates.firstWhereOrNull(
(t) =>
t.country == shippingCountry.countryCode &&
t.postcode == postalCode,
);
taxRate ??= _taxRates.firstWhereOrNull(
(t) => t.country == shippingCountry.countryCode,
);
}
if (taxRate != null) {
_taxRate = taxRate;
}
setState(() {
_showFullLoader = false;
});
}
@override
Widget build(BuildContext context) {
CheckoutSession checkoutSession = CheckoutSession.getInstance;
if (_showFullLoader == true) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AppLoaderWidget(),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
"${trans("One moment")}...",
style: Theme.of(context).textTheme.titleMedium,
),
)
],
),
),
);
}
return Scaffold(
appBar: AppBar(
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(trans("Checkout")),
Text(_wooSignalApp?.appName ?? getEnv('APP_NAME')).bodySmall(context),
],
),
centerTitle: false,
leading: Container(
child: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
CheckoutSession.getInstance.coupon = null;
Navigator.pop(context);
},
),
margin: EdgeInsets.only(left: 0),
),
),
resizeToAvoidBottomInset: false,
body: SafeAreaWidget(
child: Container(
child: ListView(
shrinkWrap: true,
children: <Widget>[
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
CheckoutStoreHeadingWidget(),
CheckoutUserDetailsWidget(
context: context,
checkoutSession: checkoutSession,
resetState: () {
setState(() {
_showFullLoader = true;
});
_getTaxes();
},
),
CheckoutPaymentTypeWidget(
context: context,
checkoutSession: checkoutSession,
resetState: () => setState(() {}),
),
CheckoutShippingTypeWidget(
context: context,
checkoutSession: checkoutSession,
resetState: () => setState(() {}),
wooSignalApp: _wooSignalApp,
),
if (_wooSignalApp!.couponEnabled == true)
CheckoutSelectCouponWidget(
context: context,
checkoutSession: checkoutSession,
resetState: () => setState(() {}),
),
Container(
decoration: BoxDecoration(
boxShadow: wsBoxShadow(),
color: Colors.white,
// borderRadius: BorderRadius.circular(16)
),
padding: EdgeInsets.symmetric(vertical: 16),
margin: EdgeInsets.only(top: 20),
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Row(
children: [
Icon(Icons.receipt),
Padding(padding: EdgeInsets.only(right: 8),),
Text(trans("Order Summary")).fontWeightBold()
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(padding: EdgeInsets.only(top: 16)),
CheckoutSubtotal(
title: trans("Subtotal"),
),
CheckoutCouponAmountWidget(
checkoutSession: checkoutSession),
if (_wooSignalApp!.disableShipping != 1)
CheckoutMetaLine(
title: trans("Shipping fee"),
amount: CheckoutSession
.getInstance.shippingType ==
null
? trans("Select shipping")
: CheckoutSession
.getInstance.shippingType!
.getTotal(withFormatting: true)),
if (_taxRate != null)
CheckoutTaxTotal(taxRate: _taxRate),
Padding(padding: EdgeInsets.only(top: 8, left: 8, right: 8)),
Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: RichText(
textAlign: TextAlign.left,
text: TextSpan(
text:
'${trans('By completing this order, I agree to all')} ',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 12,
),
children: <TextSpan>[
TextSpan(
recognizer: TapGestureRecognizer()..onTap = _openTermsLink,
text: trans("Terms and conditions").toLowerCase(),
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ThemeColor.get(context)
.primaryAccent,
fontSize: 12,
),
),
TextSpan(
text: ".",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: Colors.black87,
fontSize: 12,
),
),
],
),
)),
],
),
],
),
)
],
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16)
),
child: Column(
children: [
CheckoutTotal(title: trans("Total"), taxRate: _taxRate),
Padding(padding: EdgeInsets.only(bottom: 8)),
PrimaryButton(
title: _isProcessingPayment
? "${trans("PROCESSING")}..."
: trans("CHECKOUT"),
action: _isProcessingPayment ? null : _handleCheckout,
),
],
),
)
],
),
),
),
);
}
_openTermsLink() => openBrowserTab(url: AppHelper.instance.appConfig?.appTermsLink ?? "");
_handleCheckout() async {
CheckoutSession checkoutSession = CheckoutSession.getInstance;
if (checkoutSession.billingDetails!.billingAddress == null) {
showToastNotification(
context,
title: trans("Oops"),
description:
trans("Please select add your billing/shipping address to proceed"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping,
);
return;
}
if (checkoutSession.billingDetails?.billingAddress?.hasMissingFields() ??
true) {
showToastNotification(
context,
title: trans("Oops"),
description: trans("Your billing/shipping details are incomplete"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping,
);
return;
}
if (_wooSignalApp!.disableShipping == 0 &&
checkoutSession.shippingType == null) {
showToastNotification(
context,
title: trans("Oops"),
description: trans("Please select a shipping method to proceed"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping,
);
return;
}
if (checkoutSession.paymentType == null) {
showToastNotification(
context,
title: trans("Oops"),
description: trans("Please select a payment method to proceed"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.payment,
);
return;
}
if (_wooSignalApp!.disableShipping == 0 &&
checkoutSession.shippingType?.minimumValue != null) {
String total = await Cart.getInstance.getTotal();
double doubleTotal = double.parse(total);
double doubleMinimumValue =
double.parse(checkoutSession.shippingType!.minimumValue!);
if (doubleTotal < doubleMinimumValue) {
showToastNotification(context,
title: trans("Sorry"),
description:
"${trans("Spend a minimum of")} ${formatDoubleCurrency(total: doubleMinimumValue)} ${trans("for")} ${checkoutSession.shippingType!.getTitle()}",
style: ToastNotificationStyleType.INFO,
duration: Duration(seconds: 3));
return;
}
}
bool appStatus = await (appWooSignal((api) => api.checkAppStatus()));
if (!appStatus) {
showToastNotification(context,
title: trans("Sorry"),
description: trans("Retry later"),
style: ToastNotificationStyleType.INFO,
duration: Duration(seconds: 3));
return;
}
if (_isProcessingPayment == true) {
return;
}
setState(() {
_isProcessingPayment = true;
});
try {
await checkoutSession.paymentType!
.pay(context, state: this, taxRate: _taxRate);
} on Exception catch (e) {
print(e.toString());
}
setState(() {
_isProcessingPayment = false;
});
}
}