|
|
@@ -1,9 +1,17 @@
|
|
|
"use client";
|
|
|
|
|
|
-import {useState, useRef, useEffect } from "react";
|
|
|
-import { LoadingSpinner } from "@components/common/LoadingSpinner";
|
|
|
-import CheckoutShippingMethodLoading from "./CheckoutShippingMethodLoading";
|
|
|
+import {useState, useRef, useEffect, useCallback } from "react";
|
|
|
+import clsx from "clsx";
|
|
|
import { useForm, FormProvider } from "react-hook-form";
|
|
|
+import { useCustomToast } from "@/utils/hooks/useToast";
|
|
|
+import {useCheckoutAddress} from "@/utils/hooks/useCheckoutAddress"
|
|
|
+import {useCheckoutPaymentMethod} from "@/utils/hooks/useCheckoutPaymentMethod";
|
|
|
+import {useCheckoutShippingMethod} from "@/utils/hooks/useCheckoutShippingMethod";
|
|
|
+import { useAppDispatch } from "@/store/hooks";
|
|
|
+import { updateCart, clearCart } from "@/store/slices/cart-slice";
|
|
|
+import {useSaveCheckoutCart} from "@/utils/hooks/useSaveCheckoutCart";
|
|
|
+import { usePlaceOrder } from "@/utils/hooks/usePlaceOrder";
|
|
|
+import {usePaymentSDKContext} from "@/providers/PaymentSDKProvider";
|
|
|
import {
|
|
|
ShipAddressFormData,
|
|
|
FullAddressFormData,
|
|
|
@@ -12,31 +20,26 @@ import {
|
|
|
PlaceOrderFunction,
|
|
|
CreatePaymentInitiateVariables
|
|
|
} from "@/types/checkout/type";
|
|
|
+import { CartDetail,CartAddress } from "@/types/cart/type";
|
|
|
+import { formatCartDetail } from "@/utils/cartDetailTools";
|
|
|
+import { overlayLoading } from "@/components/theme/ui/kernel/loading/api";
|
|
|
+import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api";
|
|
|
+import {normalizePhoneForForm} from "@/utils/phoneNumberTools";
|
|
|
+import { LoadingSpinner } from "@components/common/LoadingSpinner";
|
|
|
+import CheckoutShippingMethodLoading from "./CheckoutShippingMethodLoading";
|
|
|
import AddressResultDisplay from "./AddressResultDisplay";
|
|
|
import ShippingAddressCheckout from "./ShippingAddressCheckout";
|
|
|
import BillingAddressCheckout from "./BillingAddressCheckout";
|
|
|
import {ShippingMethodCheckout,RefShippingMethodsHandle} from "./ShippingMethodCheckout";
|
|
|
-import { useCustomToast } from "@/utils/hooks/useToast";
|
|
|
-import {useCheckoutAddress} from "@/utils/hooks/useCheckoutAddress"
|
|
|
-import {useCheckoutPaymentMethod} from "@/utils/hooks/useCheckoutPaymentMethod";
|
|
|
-import {useCheckoutShippingMethod} from "@/utils/hooks/useCheckoutShippingMethod";
|
|
|
-import { useAppDispatch } from "@/store/hooks";
|
|
|
-import { updateCart } from "@/store/slices/cart-slice";
|
|
|
import {PaymentMethodCheckout,RefPaymentMethodsHandle} from "./PaymentMethodCheckout";
|
|
|
import LoadingPaymentMethod from "./LoadingPaymentMethod";
|
|
|
import LoadingCheckoutPlaceOrder from "./LoadingCheckoutPlaceOrder";
|
|
|
import CheckoutPlaceOrder from "./CheckoutPlaceOrder";
|
|
|
import CommonModal from "@/components/theme/ui/CommonModal";
|
|
|
-import {useSaveCheckoutCart} from "@/utils/hooks/useSaveCheckoutCart";
|
|
|
-import { formatCartDetail, shippingAddressToCartAddress, billingAddressToCartAddress } from "@/utils/cartDetailTools";
|
|
|
-import { overlayLoading } from "@/components/theme/ui/kernel/loading/api";
|
|
|
-import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api";
|
|
|
-import { CartDetail,CartAddress } from "@/types/cart/type";
|
|
|
-import {normalizePhoneForForm} from "@/utils/phoneNumberTools";
|
|
|
-import { usePlaceOrder } from "@/utils/hooks/usePlaceOrder";
|
|
|
-import { clearCart } from "@/store/slices/cart-slice";
|
|
|
import PaypalApplepayButton from "./PaymentButton/PaypalApplepayButton";
|
|
|
-import {usePaymentSDKContext} from "@/providers/PaymentSDKProvider";
|
|
|
+import CheckoutGiftCardGate from "./GiftCard/CheckoutGiftCardGate";
|
|
|
+import PromotionsDetails from "./PromotionsDetails";
|
|
|
+
|
|
|
/***
|
|
|
* 不用useForShipping字段了
|
|
|
* 以shipping address 为准,根据shippingaddress 设置billing address
|
|
|
@@ -250,7 +253,7 @@ export default function CheckoutWrapper({
|
|
|
} = useCheckoutPaymentMethod();
|
|
|
|
|
|
const { showToast } = useCustomToast();
|
|
|
- const { getCheckoutAddress, saveCheckoutAddress } = useCheckoutAddress(loginEmail);
|
|
|
+ const { saveCheckoutAddress } = useCheckoutAddress(loginEmail);
|
|
|
|
|
|
const methodShiippingRef = useRef<RefShippingMethodsHandle>(null);
|
|
|
const methodPaymentRef = useRef<RefPaymentMethodsHandle>(null);
|
|
|
@@ -283,6 +286,15 @@ export default function CheckoutWrapper({
|
|
|
changePaymentMethodToloadSdk(selectedPaymentMethod);
|
|
|
}, [selectedPaymentMethod]);
|
|
|
|
|
|
+
|
|
|
+ const dispatchCartStore = useCallback((action: "clear" | "update", payload?:Partial<CartDetail>) => {
|
|
|
+ if(action === "clear") {
|
|
|
+ dispatch(clearCart());
|
|
|
+ } else if(action === "update" && payload) {
|
|
|
+ dispatch(updateCart(payload));
|
|
|
+ }
|
|
|
+ },[dispatch]);
|
|
|
+
|
|
|
const openAddressModal = () => {
|
|
|
setAddressModalOpen(true);
|
|
|
|
|
|
@@ -308,35 +320,65 @@ export default function CheckoutWrapper({
|
|
|
setAddressSaving(true);
|
|
|
try {
|
|
|
|
|
|
- const res = await saveCheckoutAddress(saveAddressParam);
|
|
|
- console.log('CREATE_CHECKOUT_ADDRESS res ====== ',res);
|
|
|
- // 地址保存成功后重新获取运输方式和支付方式
|
|
|
- await getShippingMethod();
|
|
|
- await getPaymentMethod();
|
|
|
-
|
|
|
- // 保存完地址之后还要重新请求地址,把保存后的地址id同步到表单里;
|
|
|
- const queryAddressRes = await getCheckoutAddress();
|
|
|
- if(queryAddressRes !== null) {
|
|
|
- addressForm.resetField('shippingAddressId',{
|
|
|
- defaultValue: queryAddressRes.shippingAddress.shippingAddressId
|
|
|
- });
|
|
|
- addressForm.resetField('billingAddressId',{
|
|
|
- defaultValue: queryAddressRes.billingAddress.billingAddressId
|
|
|
- });
|
|
|
-
|
|
|
-
|
|
|
- // 同步地址到购物车详情
|
|
|
- const newBillingAddress = billingAddressToCartAddress(queryAddressRes.billingAddress);
|
|
|
- const newShippingAddress = shippingAddressToCartAddress(queryAddressRes.shippingAddress);
|
|
|
- dispatch(updateCart({
|
|
|
- billingAddress: newBillingAddress,
|
|
|
- shippingAddress: newShippingAddress
|
|
|
- }));
|
|
|
- setCartData(Object.assign({...cartData},{
|
|
|
- billingAddress: {...newBillingAddress},
|
|
|
- shippingAddress: {...newShippingAddress}
|
|
|
- }));
|
|
|
+ const saveRes = await saveCheckoutAddress(saveAddressParam);
|
|
|
+ console.log('CREATE_CHECKOUT_ADDRESS res ====== ',saveRes);
|
|
|
+ if(!saveRes.error) {
|
|
|
+ // 地址保存成功后重新获取运输方式和支付方式
|
|
|
+ // await getShippingMethod();
|
|
|
+ // await getPaymentMethod();
|
|
|
+ await Promise.all([getShippingMethod(),getPaymentMethod()]);
|
|
|
+
|
|
|
+ // 保存完地址之后,把保存后的地址id同步到表单里;
|
|
|
+ const createAddressData = saveRes.data;
|
|
|
+ if(createAddressData !== null) {
|
|
|
+ addressForm.resetField('shippingAddressId',{
|
|
|
+ defaultValue: createAddressData.shippingAddressId
|
|
|
+ });
|
|
|
+ addressForm.resetField('billingAddressId',{
|
|
|
+ defaultValue: createAddressData.billingAddressId
|
|
|
+ });
|
|
|
|
|
|
+
|
|
|
+ // 同步地址到购物车详情
|
|
|
+ const newBillingAddress = {
|
|
|
+ id: String(createAddressData.billingAddressId),
|
|
|
+ firstName: createAddressData.billingFirstName,
|
|
|
+ lastName: createAddressData.billingLastName,
|
|
|
+ email: createAddressData.billingEmail,
|
|
|
+ address: createAddressData.billingAddress,
|
|
|
+ city: createAddressData.billingCity,
|
|
|
+ state: createAddressData.billingState,
|
|
|
+ country: createAddressData.billingCountry,
|
|
|
+ postcode: createAddressData.billingPostcode,
|
|
|
+ phone: createAddressData.billingPhoneNumber
|
|
|
+ };
|
|
|
+ const newShippingAddress = {
|
|
|
+ id: String(createAddressData.shippingAddressId),
|
|
|
+ firstName: createAddressData.shippingFirstName,
|
|
|
+ lastName: createAddressData.shippingLastName,
|
|
|
+ email: createAddressData.shippingEmail,
|
|
|
+ address: createAddressData.shippingAddress,
|
|
|
+ city: createAddressData.shippingCity,
|
|
|
+ state: createAddressData.shippingState,
|
|
|
+ country: createAddressData.shippingCountry,
|
|
|
+ postcode: createAddressData.shippingPostcode,
|
|
|
+ phone: createAddressData.shippingPhoneNumber,
|
|
|
+ };
|
|
|
+ dispatchCartStore('update',{
|
|
|
+ billingAddress: newBillingAddress,
|
|
|
+ shippingAddress: newShippingAddress
|
|
|
+ });
|
|
|
+ setCartData(Object.assign({...cartData},{
|
|
|
+ billingAddress: {...newBillingAddress},
|
|
|
+ shippingAddress: {...newShippingAddress}
|
|
|
+ }));
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // 提示用户出错了,刷新页面
|
|
|
+ showToast('Something wrong. Please refresh the page.', 'danger');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ showToast(saveRes.msg, 'danger');
|
|
|
}
|
|
|
setAddressModalOpen(false);
|
|
|
} catch(err) {
|
|
|
@@ -353,21 +395,23 @@ export default function CheckoutWrapper({
|
|
|
|
|
|
const handlePaymentMethodChange = async (method: string) => {
|
|
|
changePaymentMethodToloadSdk(method);
|
|
|
- let shippingMethod = '-1';
|
|
|
- if(methodShiippingRef.current) {
|
|
|
- shippingMethod = methodShiippingRef.current.getSelectShipMethod();
|
|
|
- }
|
|
|
+ // let shippingMethod = '-1';
|
|
|
+ // if(methodShiippingRef.current) {
|
|
|
+ // shippingMethod = methodShiippingRef.current.getSelectShipMethod();
|
|
|
+ // }
|
|
|
overlayLoading.start();
|
|
|
const saveRes = await saveCheckoutCart({
|
|
|
- shippingMethod: shippingMethod,
|
|
|
+ shippingMethod: '-1',
|
|
|
paymentMethod: method,
|
|
|
- couponCode: '-1'
|
|
|
+ couponCode: '-1',
|
|
|
+ giftCardNumber: '-1',
|
|
|
+ memberDiscount: '-1'
|
|
|
});
|
|
|
overlayLoading.stop();
|
|
|
if(!saveRes.error) {
|
|
|
if(saveRes.data) {
|
|
|
const newCartDetail = formatCartDetail(saveRes.data);
|
|
|
- dispatch(updateCart(newCartDetail));
|
|
|
+ dispatchCartStore('update',newCartDetail);
|
|
|
setCartData({...newCartDetail});
|
|
|
}
|
|
|
return true;
|
|
|
@@ -377,18 +421,20 @@ export default function CheckoutWrapper({
|
|
|
}
|
|
|
|
|
|
};
|
|
|
- const handleShippingMethodChange = async (method: string) => {
|
|
|
+ const handleShippingMethodChange = useCallback(async (method: string) => {
|
|
|
overlayLoading.start();
|
|
|
const saveRes = await saveCheckoutCart({
|
|
|
shippingMethod: method,
|
|
|
paymentMethod: '-1',
|
|
|
- couponCode: '-1'
|
|
|
+ couponCode: '-1',
|
|
|
+ giftCardNumber: '-1',
|
|
|
+ memberDiscount: '-1'
|
|
|
});
|
|
|
overlayLoading.stop();
|
|
|
if(!saveRes.error) {
|
|
|
if(saveRes.data) {
|
|
|
const newCartDetail = formatCartDetail(saveRes.data);
|
|
|
- dispatch(updateCart(newCartDetail));
|
|
|
+ dispatchCartStore('update',newCartDetail);
|
|
|
setCartData({...newCartDetail});
|
|
|
}
|
|
|
// 保存成功之后需要重新获取支付方式
|
|
|
@@ -397,11 +443,11 @@ export default function CheckoutWrapper({
|
|
|
showToast(saveRes.msg, 'danger');
|
|
|
}
|
|
|
|
|
|
- };
|
|
|
+ },[saveCheckoutCart,showToast,getPaymentMethod,dispatchCartStore]);
|
|
|
|
|
|
|
|
|
// 校验地址 运输方式,支付方式;
|
|
|
- const validateCheckout = async () => {
|
|
|
+ const validateCheckout = useCallback(async () => {
|
|
|
const addressValid = await addressForm.trigger();
|
|
|
|
|
|
if(!addressValid) {
|
|
|
@@ -446,26 +492,30 @@ export default function CheckoutWrapper({
|
|
|
const saveRes = await saveCheckoutCart({
|
|
|
shippingMethod: '-1',
|
|
|
paymentMethod: pmethod,
|
|
|
- couponCode: '-1'
|
|
|
+ couponCode: '-1',
|
|
|
+ giftCardNumber: '-1',
|
|
|
+ memberDiscount: '-1'
|
|
|
});
|
|
|
if(!saveRes.error) {
|
|
|
if(saveRes.data) {
|
|
|
const newCartDetail = formatCartDetail(saveRes.data);
|
|
|
- dispatch(updateCart(newCartDetail));
|
|
|
+ dispatchCartStore('update',newCartDetail);
|
|
|
setCartData({...newCartDetail});
|
|
|
}
|
|
|
+ } else {
|
|
|
+ showToast(saveRes.msg, 'danger');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
- };
|
|
|
+ },[addressForm,showToast,saveCheckoutCart,dispatchCartStore]);
|
|
|
// 苹果支付下单
|
|
|
- const applepayPlaceOrder = async () => {
|
|
|
+ const applepayPlaceOrder = useCallback(async () => {
|
|
|
const res = await createOrder();
|
|
|
if(!res.error) {
|
|
|
//创建订单成功后清空redux 购物车
|
|
|
- dispatch(clearCart());
|
|
|
+ dispatchCartStore('clear');
|
|
|
return {
|
|
|
orderId: res.data?.gatewayOrderId ?? '',
|
|
|
webOrderId: res.data?.orderId ?? ''
|
|
|
@@ -474,24 +524,20 @@ export default function CheckoutWrapper({
|
|
|
// 抛出错误让第三方支付能够捕获
|
|
|
throw new Error("CREATE_ORDER_ERROR: " + res.msg);
|
|
|
}
|
|
|
- };
|
|
|
- // 下单
|
|
|
+ },[createOrder,dispatchCartStore]);
|
|
|
+ // 下单(下单和校验分开)
|
|
|
const handlePlaceOrder: PlaceOrderFunction = async <T,>(params?: CreatePaymentInitiateVariables): Promise<PlaceOrderResult<T>> => {
|
|
|
- // 校验地址
|
|
|
- // overlayLoading.start();
|
|
|
- // const validRes = await validateCheckout();
|
|
|
- // if(validRes) {
|
|
|
const res = await createOrder(params);
|
|
|
if(res.error) {
|
|
|
overlayLoading.stop();
|
|
|
confirmDialog({
|
|
|
title: "Warning",
|
|
|
- content: res.msg + " Create order failed. Please try again.",
|
|
|
+ content: res.msg + ". Create order failed. Please try again.",
|
|
|
noCancel: true,
|
|
|
}).then(() => {});
|
|
|
} else {
|
|
|
//创建订单成功后清空redux 购物车
|
|
|
- dispatch(clearCart());
|
|
|
+ dispatchCartStore('clear');
|
|
|
}
|
|
|
const pmethod = methodPaymentRef.current?.getSelectPaymentMethod();
|
|
|
let resultData: PlaceOrderResult<T>;
|
|
|
@@ -518,12 +564,16 @@ export default function CheckoutWrapper({
|
|
|
};
|
|
|
}
|
|
|
return resultData;
|
|
|
- // } else {
|
|
|
- // overlayLoading.stop();
|
|
|
- // return {valid: false, data: null, otherData: null};
|
|
|
- // }
|
|
|
}
|
|
|
|
|
|
+ const onChangeGiftcard = async (paylod: CartDetail) => {
|
|
|
+ dispatchCartStore('update',paylod);
|
|
|
+ setCartData({...paylod});
|
|
|
+ // @todo 还要请求支付方式和运输方式
|
|
|
+ // await getShippingMethod();
|
|
|
+ // await getPaymentMethod();
|
|
|
+ await Promise.all([getShippingMethod(),getPaymentMethod()]);
|
|
|
+ };
|
|
|
|
|
|
// function tt() {
|
|
|
// const arr = [
|
|
|
@@ -603,42 +653,52 @@ export default function CheckoutWrapper({
|
|
|
</div>
|
|
|
<div className="mt-6 box-border px-4">
|
|
|
<h3 className="text-ly-24 font-medium" onClick={testEruda}>Shipping Method</h3>
|
|
|
- {shippingMethodLoading ?
|
|
|
-
|
|
|
- <CheckoutShippingMethodLoading />
|
|
|
- :
|
|
|
- <ShippingMethodCheckout
|
|
|
- ref={methodShiippingRef}
|
|
|
- shipMethods={shippingMethodDatas}
|
|
|
- errorMsg={shippingMethodError}
|
|
|
- selectedShippingRate={selectedShippingRate}
|
|
|
- onShipMethodChange={handleShippingMethodChange}
|
|
|
- />
|
|
|
- }
|
|
|
+
|
|
|
+ <ShippingMethodCheckout
|
|
|
+ ref={methodShiippingRef}
|
|
|
+ shipMethods={shippingMethodDatas}
|
|
|
+ errorMsg={shippingMethodError}
|
|
|
+ selectedShippingRate={selectedShippingRate}
|
|
|
+ shippingMethodLoading={shippingMethodLoading}
|
|
|
+ onShipMethodChange={handleShippingMethodChange}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
|
|
|
+ <div className="mt-6 box-border px-4">
|
|
|
+ <CheckoutGiftCardGate
|
|
|
+ giftcardNumber={cartData.giftcardNumber || ''}
|
|
|
+ formattedGiftcardAmount={cartData.formattedGiftcardAmount}
|
|
|
+ onChangeGiftcard={onChangeGiftcard}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="mt-6 box-border px-4">
|
|
|
+ <h3 className="text-ly-24 font-medium">Promotion Details</h3>
|
|
|
+ <div className="w-full box-border mt-3">
|
|
|
+ <PromotionsDetails cartData={cartData} />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<div className="mt-6 box-border px-4">
|
|
|
<h3 className="text-ly-24 font-medium">Payment Method</h3>
|
|
|
- { paymentMethodLoading && <LoadingPaymentMethod /> }
|
|
|
- { (!paymentMethodLoading && paymentMethodError) && <p className="mt-3 text-red-500 text-ly-12">{paymentMethodError}</p>}
|
|
|
- { (!paymentMethodLoading && !paymentMethodError) &&
|
|
|
- <PaymentMethodCheckout
|
|
|
- ref={methodPaymentRef}
|
|
|
- paymentMethods={paymentMethodDatas}
|
|
|
- selectedPaymentMethod={selectedPaymentMethod}
|
|
|
- onPaymentMethodChange={handlePaymentMethodChange}
|
|
|
- />
|
|
|
- }
|
|
|
+ <PaymentMethodCheckout
|
|
|
+ ref={methodPaymentRef}
|
|
|
+ paymentMethods={paymentMethodDatas}
|
|
|
+ selectedPaymentMethod={selectedPaymentMethod}
|
|
|
+ paymentMethodLoading={paymentMethodLoading}
|
|
|
+ onPaymentMethodChange={handlePaymentMethodChange}
|
|
|
+ />
|
|
|
+
|
|
|
|
|
|
</div>
|
|
|
<div className="mt-3 box-border px-4 pb-8">
|
|
|
<p className="text-ly-12 text-[#666666] leading-ly-20">By providing your information, you agree to Wiggins'sPrivacy Policyand Terms of Use.</p>
|
|
|
<div className="mt-6 w-full">
|
|
|
- { paymentMethodLoading ?
|
|
|
- <LoadingCheckoutPlaceOrder />
|
|
|
- :
|
|
|
- (selectedPaymentMethod === 'applepay' ?
|
|
|
+ { paymentMethodLoading && <LoadingCheckoutPlaceOrder />}
|
|
|
+
|
|
|
+ <div className={clsx("w-full",{
|
|
|
+ "hidden": selectedPaymentMethod !== 'applepay' || paymentMethodLoading
|
|
|
+ })}>
|
|
|
<PaypalApplepayButton
|
|
|
grandTotal={cartData.grandTotal}
|
|
|
billingContact={cartData.billingAddress}
|
|
|
@@ -646,14 +706,17 @@ export default function CheckoutWrapper({
|
|
|
validateCheckout={validateCheckout}
|
|
|
createOrder={applepayPlaceOrder}
|
|
|
/>
|
|
|
- :
|
|
|
+ </div>
|
|
|
+ <div className={clsx("w-full",{
|
|
|
+ "hidden": selectedPaymentMethod === 'applepay' || paymentMethodLoading
|
|
|
+ })}>
|
|
|
<CheckoutPlaceOrder
|
|
|
paymentMethod={selectedPaymentMethod}
|
|
|
validateCheckout={validateCheckout}
|
|
|
clickPlaceOrder={handlePlaceOrder}
|
|
|
- />)
|
|
|
-
|
|
|
- }
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
</div>
|
|
|
</div>
|
|
|
|