|
|
@@ -0,0 +1,435 @@
|
|
|
+"use client";
|
|
|
+
|
|
|
+import clsx from "clsx";
|
|
|
+import { useState,useCallback } from "react";
|
|
|
+import { useRouter } from 'next/navigation'
|
|
|
+import { useCustomToast } from "@/utils/hooks/useToast";
|
|
|
+import {
|
|
|
+ airwallexManager
|
|
|
+} from "@/lib/Airwallex/useAirwallexCard";
|
|
|
+import type { OrderDetails } from "@/types/customer/type";
|
|
|
+import { usePlaceOrder } from "@/utils/hooks/usePlaceOrder";
|
|
|
+import PaypalButton from "../PaymentButton/PaypalButton";
|
|
|
+import { overlayLoading } from "@/components/theme/ui/kernel/loading/api";
|
|
|
+import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api";
|
|
|
+import PaypalApplepayButton from "../PaymentButton/PaypalApplepayButton";
|
|
|
+import KlarnaButton from "../PaymentButton/KlarnaButton";
|
|
|
+import {getAddressFromOrderDetailAddressList} from "@/utils/orderDetailTools";
|
|
|
+
|
|
|
+
|
|
|
+export function ContinueCheckout({
|
|
|
+ selectedPaymentMethod,
|
|
|
+ orderDetail
|
|
|
+}: {
|
|
|
+ selectedPaymentMethod: string;
|
|
|
+ orderDetail: OrderDetails;
|
|
|
+}) {
|
|
|
+ const orderId = orderDetail._id;
|
|
|
+
|
|
|
+ const router = useRouter();
|
|
|
+ const { showToast } = useCustomToast();
|
|
|
+ const { paymentRepay, createPaymentCallback } = usePlaceOrder();
|
|
|
+
|
|
|
+ const orderCurrencyCode = orderDetail.orderCurrencyCode;
|
|
|
+ const [isPay, setIsPay] = useState(false);
|
|
|
+ const shippingContact = getAddressFromOrderDetailAddressList(orderDetail.addresses,"order_shipping");
|
|
|
+ const billingContact = getAddressFromOrderDetailAddressList(orderDetail.addresses,"order_billing");
|
|
|
+
|
|
|
+ const paypalRepayOrder = async () => {
|
|
|
+ overlayLoading.start();
|
|
|
+ const res = await paymentRepay({
|
|
|
+ orderId: Number(orderId),
|
|
|
+ paymentMethod: selectedPaymentMethod
|
|
|
+ });
|
|
|
+ overlayLoading.stop();
|
|
|
+ if(!res.error && res.data !== null) {
|
|
|
+ return {
|
|
|
+ error: false,
|
|
|
+ msg: '',
|
|
|
+ orderId: res.data.gatewayOrderId,
|
|
|
+ webOrderId: res.data.orderId
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ confirmDialog({
|
|
|
+ title: "Warning",
|
|
|
+ content: res.msg + " Create order failed. Please try again.",
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {});
|
|
|
+ return {
|
|
|
+ error: true,
|
|
|
+ msg: '',
|
|
|
+ orderId: '',
|
|
|
+ webOrderId: ''
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ const airwallexRepay = async () => {
|
|
|
+ setIsPay(true);
|
|
|
+ overlayLoading.start();
|
|
|
+ const res = await paymentRepay({
|
|
|
+ orderId: Number(orderId),
|
|
|
+ paymentMethod: selectedPaymentMethod,
|
|
|
+ paymentSuccessUrl: window.location.origin + '/paymentresult/result'
|
|
|
+ });
|
|
|
+
|
|
|
+ if(!res.error && res.data !== null) {
|
|
|
+ // 创建订单成功了,跳转支付页面
|
|
|
+ window.location.href = res.data.gatewayOrderId;
|
|
|
+ } else {
|
|
|
+ //创建订单出错了
|
|
|
+ overlayLoading.stop();
|
|
|
+ confirmDialog({
|
|
|
+ title: "Warning",
|
|
|
+ content: res.msg + " Create order failed. Please try again.",
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {});
|
|
|
+ }
|
|
|
+ setIsPay(false);
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ const validateAirwallexCard = () => {
|
|
|
+
|
|
|
+ const res = airwallexManager.validateCard();
|
|
|
+ if(res.msg) {
|
|
|
+ showToast(res.msg, 'danger');
|
|
|
+ }
|
|
|
+ return res.valid;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ const cardAirwallexRepay = async () => {
|
|
|
+ setIsPay(true);
|
|
|
+ overlayLoading.start();
|
|
|
+ const validRes = validateAirwallexCard();
|
|
|
+ if(validRes) {
|
|
|
+
|
|
|
+ const res = await paymentRepay({
|
|
|
+ orderId: Number(orderId),
|
|
|
+ paymentMethod: selectedPaymentMethod,
|
|
|
+ });
|
|
|
+
|
|
|
+ if(!res.error && res.data !== null) {
|
|
|
+ // 创建订单成功
|
|
|
+ const cardNumberElement = airwallexManager.getCardNumberElement();
|
|
|
+ const paymentIntentIdClientSecret = res.data.gatewayOrderId.split(':');
|
|
|
+ const paymentIntentId = paymentIntentIdClientSecret[0];
|
|
|
+ const paymentIntentClientSecret = paymentIntentIdClientSecret[1];
|
|
|
+
|
|
|
+ cardNumberElement?.confirm({
|
|
|
+ intent_id: paymentIntentId,
|
|
|
+ client_secret: paymentIntentClientSecret,
|
|
|
+ }).then((result) => {
|
|
|
+ overlayLoading.stop();
|
|
|
+ console.log('cardNumberElement.confirm result ---- ', result);
|
|
|
+ // 支付成功 跳转页面
|
|
|
+ router.replace('/paymentresult/result?orderId=' + orderId + '&return_result=success');
|
|
|
+ }).catch((error) => {
|
|
|
+ overlayLoading.stop();
|
|
|
+ console.log('cardNumberElement.confirm error ---- ', error);
|
|
|
+ // 支付失败
|
|
|
+ router.replace('/paymentresult/result?orderId=' + orderId + '&return_result=failure');
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ //创建订单出错了
|
|
|
+ overlayLoading.stop();
|
|
|
+ confirmDialog({
|
|
|
+ title: "Warning",
|
|
|
+ content: res.msg + " Create order failed. Please try again.",
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {});
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ overlayLoading.stop();
|
|
|
+ }
|
|
|
+ setIsPay(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const afterpayPlaceOrder = async () => {
|
|
|
+ setIsPay(true);
|
|
|
+ overlayLoading.start();
|
|
|
+ if(window.AfterPay) {
|
|
|
+
|
|
|
+ const res = await paymentRepay({
|
|
|
+ orderId: Number(orderId),
|
|
|
+ paymentMethod: selectedPaymentMethod,
|
|
|
+ paymentSuccessUrl: window.location.origin + '/paymentresult/result',
|
|
|
+ paymentCancelUrl: window.location.origin + '/paymentresult/result'
|
|
|
+ });
|
|
|
+
|
|
|
+ if(!res.error && res.data !== null) {
|
|
|
+ const afterpayToken = res.data.gatewayOrderId;
|
|
|
+ const webOrderId = res.data.orderId;
|
|
|
+ let countryCode = "US";
|
|
|
+ if(orderCurrencyCode === "CAD") {
|
|
|
+ countryCode = "CA";
|
|
|
+ } else if(orderCurrencyCode === "AUD") {
|
|
|
+ countryCode = "AU";
|
|
|
+ } else if(orderCurrencyCode === "NZD") {
|
|
|
+ countryCode = "NZ";
|
|
|
+ } else if(orderCurrencyCode === "GBP") {
|
|
|
+ countryCode = "GB";
|
|
|
+ }
|
|
|
+ window.AfterPay.initialize({countryCode: countryCode});
|
|
|
+ // To avoid triggering browser anti-popup rules, the AfterPay.open()
|
|
|
+ // function must be directly called inside the click event listener
|
|
|
+ window.AfterPay.open();
|
|
|
+ // If you don't already have a checkout token at this point, you can
|
|
|
+ // AJAX to your backend to retrieve one here. The spinning animation
|
|
|
+ // will continue until `AfterPay.transfer` is called.
|
|
|
+ // If you fail to get a token you can call AfterPay.close()
|
|
|
+ window.AfterPay.onComplete = async (event) => {
|
|
|
+ console.log('window.AfterPay.onComplete event ---- ', event);
|
|
|
+ const status: "success" | "cancel" | "failure" = event.data.status === "SUCCESS" ? 'success' : 'cancel';
|
|
|
+ const resCallback = await createPaymentCallback({
|
|
|
+ orderId: Number(webOrderId),
|
|
|
+ gatewayOrderId: event.data.orderToken,
|
|
|
+ status: status,
|
|
|
+ });
|
|
|
+ overlayLoading.stop();
|
|
|
+ if (event.data.status == "SUCCESS") {
|
|
|
+ // The customer confirmed the payment schedule.
|
|
|
+ // The token is now ready to be captured from your server backend.
|
|
|
+ // 跳转结果页 成功
|
|
|
+ if(!resCallback.error) {
|
|
|
+ // 后端capture成功,跳转到成功落地页
|
|
|
+ router.replace('/paymentresult/result?orderId=' + webOrderId + '&return_result=success');
|
|
|
+ } else {
|
|
|
+ // capture 失败,提示错误
|
|
|
+ confirmDialog({
|
|
|
+ title: "Somthing Wrong",
|
|
|
+ content: resCallback.msg + " Please contact customer service." + " OrderId: "+ webOrderId,
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {
|
|
|
+ router.replace('/');
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // The customer cancelled the payment or closed the popup window.
|
|
|
+ confirmDialog({
|
|
|
+ title: "Payment Cancelled",
|
|
|
+ content: "You canceled the payment.",
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => { });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ window.AfterPay.transfer({token: afterpayToken});
|
|
|
+ } else {
|
|
|
+ //创建订单出错了
|
|
|
+ overlayLoading.stop();
|
|
|
+ confirmDialog({
|
|
|
+ title: "Warning",
|
|
|
+ content: res.msg + " Create order failed. Please try again.",
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {});
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ overlayLoading.stop();
|
|
|
+ showToast("Please wait for the Afterpay to load completely.","warning");
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const applepayPlaceOrder = async () => {
|
|
|
+
|
|
|
+ const res = await paymentRepay({
|
|
|
+ orderId: Number(orderId),
|
|
|
+ paymentMethod: selectedPaymentMethod
|
|
|
+ });
|
|
|
+
|
|
|
+ if(!res.error && res.data !== null) {
|
|
|
+ return {
|
|
|
+ orderId: res.data.gatewayOrderId,
|
|
|
+ webOrderId: res.data.orderId
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ // 抛出错误让第三方支付能够捕获
|
|
|
+ throw new Error("REPAY_ORDER_ERROR: " + res.msg);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const validateCheckout = useCallback(async() => {
|
|
|
+ return true;
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const klarnaPlaceOrder = async () => {
|
|
|
+ overlayLoading.start();
|
|
|
+
|
|
|
+ const resRepay = await paymentRepay({
|
|
|
+ orderId:Number(orderId),
|
|
|
+ paymentMethod: selectedPaymentMethod,
|
|
|
+ paymentSuccessUrl: window.location.origin + '/paymentresult/result',
|
|
|
+ paymentCancelUrl: window.location.origin + '/paymentresult/result'
|
|
|
+ });
|
|
|
+
|
|
|
+ if(!resRepay.error && resRepay.data !== null) {
|
|
|
+ const klarnaToken = resRepay.data.gatewayOrderId;
|
|
|
+ const webOrderId = resRepay.data.orderId;
|
|
|
+ const billingAddress = billingContact;
|
|
|
+ const shippingAddress = shippingContact;
|
|
|
+
|
|
|
+ const klarnaClientToken = klarnaToken.split("|")[0];
|
|
|
+ // const klarnaVerifyToken = klarnaToken.split("|")[1];
|
|
|
+ window.Klarna.Payments.init({
|
|
|
+ client_token: klarnaClientToken,
|
|
|
+ });
|
|
|
+ //klarna-widget-container
|
|
|
+ window.Klarna.Payments.load({
|
|
|
+ container: '#klarna-widget-container',
|
|
|
+ }, (response) => {
|
|
|
+ if(!response.show_form) { // klarna不可用
|
|
|
+ // 跳转结果页
|
|
|
+ router.replace('/paymentresult/result?orderId=' + webOrderId + '&return_result=failure');
|
|
|
+ } else {
|
|
|
+
|
|
|
+
|
|
|
+ window.Klarna.Payments.authorize(
|
|
|
+ {},
|
|
|
+ {
|
|
|
+ billing_address: {
|
|
|
+ given_name: billingAddress.firstName,
|
|
|
+ family_name: billingAddress.lastName,
|
|
|
+ email: billingAddress.email,
|
|
|
+ phone: billingAddress.phone,
|
|
|
+ street_address: billingAddress.address,
|
|
|
+ postal_code: billingAddress.postcode,
|
|
|
+ city: billingAddress.city,
|
|
|
+ country: billingAddress.country
|
|
|
+ },
|
|
|
+ shipping_address: {
|
|
|
+ given_name: shippingAddress.firstName,
|
|
|
+ family_name: shippingAddress.lastName,
|
|
|
+ email: shippingAddress.email,
|
|
|
+ street_address: shippingAddress.address,
|
|
|
+ postal_code: shippingAddress.postcode,
|
|
|
+ city: shippingAddress.city,
|
|
|
+ phone: shippingAddress.phone,
|
|
|
+ region: shippingAddress.state,
|
|
|
+ country: shippingAddress.country
|
|
|
+ },
|
|
|
+ // customer: {
|
|
|
+ // date_of_birth: "1941-03-21",
|
|
|
+ // },
|
|
|
+ },
|
|
|
+ async function(res) {
|
|
|
+ console.log('klarna authorize res ---- ',res);
|
|
|
+ if(res.approved && res.authorization_token) { // 可以支付
|
|
|
+ overlayLoading.stop();
|
|
|
+ router.replace('/paymentresult/result?orderId=' + webOrderId + '&return_result=success');
|
|
|
+ /*
|
|
|
+ const resCallback = await createPaymentCallback({
|
|
|
+ orderId: Number(webOrderId),
|
|
|
+ gatewayOrderId: res.authorization_token,
|
|
|
+ verifyToken: klarnaVerifyToken,
|
|
|
+ status: "success",
|
|
|
+ });
|
|
|
+ // 跳转结果页
|
|
|
+ overlayLoading.stop();
|
|
|
+ if(!resCallback.error) {
|
|
|
+ router.replace('/paymentresult/result?orderId=' + webOrderId + '&return_result=success');
|
|
|
+ } else {
|
|
|
+ // callback 失败,提示错误
|
|
|
+ confirmDialog({
|
|
|
+ title: "Somthing Wrong",
|
|
|
+ content: resCallback.msg + " Please contact customer service." + " OrderId: "+ webOrderId,
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {
|
|
|
+ router.replace('/');
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+ */
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // if(res.show_form) { // klarna可用,但是有报错
|
|
|
+ // } else {
|
|
|
+ // // klarna 不可用 跳转结果页
|
|
|
+ // }
|
|
|
+ overlayLoading.stop();
|
|
|
+ router.replace('/paymentresult/result?orderId=' + webOrderId + '&return_result=failure');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ } else {
|
|
|
+ //创建订单出错了
|
|
|
+ overlayLoading.stop();
|
|
|
+ confirmDialog({
|
|
|
+ title: "Warning",
|
|
|
+ content: resRepay.msg + " Create order failed. Please try again.",
|
|
|
+ noCancel: true,
|
|
|
+ }).then(() => {});
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="w-full box-border mt-6">
|
|
|
+
|
|
|
+ <div className={clsx("w-full",{
|
|
|
+ "hidden": selectedPaymentMethod !== 'paypal_smart_button'
|
|
|
+ })}>
|
|
|
+ <PaypalButton
|
|
|
+ createOrder={paypalRepayOrder}
|
|
|
+ isRePay={true}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {(selectedPaymentMethod === 'awxklarna' || selectedPaymentMethod === 'awxafterpay') &&
|
|
|
+ <button className="flex items-center justify-center w-full h-12 bg-ly-middlegreen text-white rounded-3xl text-ly-16 font-bold"
|
|
|
+ onClick={airwallexRepay}
|
|
|
+ disabled={isPay}
|
|
|
+ >
|
|
|
+ Pay Now
|
|
|
+ </button>
|
|
|
+ }
|
|
|
+ {selectedPaymentMethod === 'airwallex' &&
|
|
|
+ <button className="flex items-center justify-center w-full h-12 bg-ly-middlegreen text-white rounded-3xl text-ly-16 font-bold"
|
|
|
+ onClick={cardAirwallexRepay}
|
|
|
+ disabled={isPay}
|
|
|
+ >
|
|
|
+ Pay Now
|
|
|
+ </button>
|
|
|
+ }
|
|
|
+ {(selectedPaymentMethod === 'afterpay' || selectedPaymentMethod === 'clearpay') &&
|
|
|
+ <button className="flex items-center justify-center w-full h-12 bg-ly-middlegreen text-white rounded-3xl text-ly-16 font-bold"
|
|
|
+ onClick={afterpayPlaceOrder}
|
|
|
+ >
|
|
|
+ Pay Now
|
|
|
+ </button>
|
|
|
+ }
|
|
|
+
|
|
|
+ <div className={clsx("w-full",{
|
|
|
+ "hidden": selectedPaymentMethod !== 'applepay'
|
|
|
+ })}>
|
|
|
+ <PaypalApplepayButton
|
|
|
+ grandTotal={orderDetail.grandTotal}
|
|
|
+ billingContact={billingContact}
|
|
|
+ shippingContact={shippingContact}
|
|
|
+ validateCheckout={validateCheckout}
|
|
|
+ createOrder={applepayPlaceOrder}
|
|
|
+ isRePay={true}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className={clsx("w-full",{
|
|
|
+ "hidden": selectedPaymentMethod !== 'klarna'
|
|
|
+ })}>
|
|
|
+ <KlarnaButton
|
|
|
+ clickHandler={klarnaPlaceOrder}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|