|
|
@@ -1,6 +1,6 @@
|
|
|
"use client";
|
|
|
|
|
|
-import {useState, useEffect, useRef} from "react";
|
|
|
+import {useState, useRef} from "react";
|
|
|
|
|
|
import { LoadingSpinner } from "@components/common/LoadingSpinner";
|
|
|
import CheckoutShippingMethodLoading from "./CheckoutShippingMethodLoading";
|
|
|
@@ -9,12 +9,10 @@ import { useForm, FormProvider } from "react-hook-form";
|
|
|
import {
|
|
|
Country,
|
|
|
ShipAddressFormData,
|
|
|
- BillAddressFormData,
|
|
|
FullAddressFormData,
|
|
|
CreateCheckoutAddressVariables,
|
|
|
} from "@/types/checkout/type";
|
|
|
import AddressResultDisplay from "./AddressResultDisplay";
|
|
|
-import AddressResultDisplayLoading from "./AddressResultDisplayLoading";
|
|
|
import ShippingAddressCheckout from "./ShippingAddressCheckout";
|
|
|
import BillingAddressCheckout from "./BillingAddressCheckout";
|
|
|
import {ShippingMethodCheckout,RefShippingMethodsHandle} from "./ShippingMethodCheckout";
|
|
|
@@ -22,17 +20,18 @@ 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,useAppStore } from "@/store/hooks";
|
|
|
+import { useAppDispatch } from "@/store/hooks";
|
|
|
import { updateCart } from "@/store/slices/cart-slice";
|
|
|
-import { useCartDetail } from "@utils/hooks/useCartDetail";
|
|
|
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 { CartDetail } from "@/types/cart/type";
|
|
|
+import { CartDetail,CartAddress } from "@/types/cart/type";
|
|
|
+import {normalizePhoneForForm} from "@/utils/phoneNumberTools";
|
|
|
/***
|
|
|
* 不用useForShipping字段了
|
|
|
* 以shipping address 为准,根据shippingaddress 设置billing address
|
|
|
@@ -41,6 +40,119 @@ import { CartDetail } from "@/types/cart/type";
|
|
|
* @todo 购物车为空 跳转到空购物车页面
|
|
|
*/
|
|
|
|
|
|
+/**
|
|
|
+ * 地址表单默认值
|
|
|
+ */
|
|
|
+function getBillingAddressFormData(billingAddress:CartAddress) {
|
|
|
+ const billingCountry = billingAddress.country || 'US';
|
|
|
+ const billingPhoneNumber = normalizePhoneForForm(billingAddress.phone, billingCountry) || "";
|
|
|
+ const res = {
|
|
|
+ "billingAddressId": billingAddress.id,
|
|
|
+ "billingEmail": billingAddress.email,
|
|
|
+ "billingFirstName": billingAddress.firstName,
|
|
|
+ "billingLastName": billingAddress.lastName,
|
|
|
+ "billingCompanyName": "",
|
|
|
+ "billingAddress": billingAddress.address,
|
|
|
+ "billingCountry": billingCountry,
|
|
|
+ "billingState": billingAddress.state,
|
|
|
+ "billingCity": billingAddress.city,
|
|
|
+ "billingPostcode": billingAddress.postcode,
|
|
|
+ "billingPhoneNumber": billingPhoneNumber,
|
|
|
+ };
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+function getShippingAddressFormData(shippingAddress:CartAddress) {
|
|
|
+ const shippingCountry = shippingAddress.country || 'US';
|
|
|
+ const shippingPhoneNumber = normalizePhoneForForm(shippingAddress.phone, shippingCountry) || "";
|
|
|
+ const res = {
|
|
|
+ "shippingAddressId": shippingAddress.id,
|
|
|
+ "shippingEmail": shippingAddress.email,
|
|
|
+ "shippingFirstName": shippingAddress.firstName,
|
|
|
+ "shippingLastName": shippingAddress.lastName,
|
|
|
+ "shippingCompanyName": "",
|
|
|
+ "shippingAddress": shippingAddress.address,
|
|
|
+ "shippingCountry": shippingCountry,
|
|
|
+ "shippingState": shippingAddress.state,
|
|
|
+ "shippingCity": shippingAddress.city,
|
|
|
+ "shippingPostcode": shippingAddress.postcode,
|
|
|
+ "shippingPhoneNumber": shippingPhoneNumber,
|
|
|
+ };
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+function getAddressFormDataFromCart(cartDetail:CartDetail, loginEmail?: string) {
|
|
|
+ const shippingAddress = cartDetail.shippingAddress;
|
|
|
+ const billingAddress = cartDetail.billingAddress;
|
|
|
+ const defaultValues = {
|
|
|
+ "shippingAddressId": "",
|
|
|
+ "shippingEmail": loginEmail ?? '',
|
|
|
+ "shippingFirstName": "",
|
|
|
+ "shippingLastName": "",
|
|
|
+ "shippingCompanyName": "",
|
|
|
+ "shippingAddress": "",
|
|
|
+ "shippingCountry": "US",
|
|
|
+ "shippingState": "",
|
|
|
+ "shippingCity": "",
|
|
|
+ "shippingPostcode": "",
|
|
|
+ "shippingPhoneNumber": "",
|
|
|
+ "billingAddressId": "",
|
|
|
+ "billingEmail": loginEmail ?? '',
|
|
|
+ "billingFirstName": "",
|
|
|
+ "billingLastName": "",
|
|
|
+ "billingCompanyName": "",
|
|
|
+ "billingAddress": "",
|
|
|
+ "billingCountry": "US",
|
|
|
+ "billingState": "",
|
|
|
+ "billingCity": "",
|
|
|
+ "billingPostcode": "",
|
|
|
+ "billingPhoneNumber": "",
|
|
|
+ "billingSameAsShipping": true
|
|
|
+ }
|
|
|
+ if(billingAddress) {
|
|
|
+ const bs = getBillingAddressFormData(billingAddress);
|
|
|
+ defaultValues.billingAddressId = bs.billingAddressId;
|
|
|
+ defaultValues.billingEmail = bs.billingEmail;
|
|
|
+ defaultValues.billingFirstName = bs.billingFirstName;
|
|
|
+ defaultValues.billingLastName = bs.billingLastName;
|
|
|
+ defaultValues.billingCompanyName = bs.billingCompanyName;
|
|
|
+ defaultValues.billingAddress = bs.billingAddress;
|
|
|
+ defaultValues.billingCountry = bs.billingCountry;
|
|
|
+ defaultValues.billingState = bs.billingState;
|
|
|
+ defaultValues.billingCity = bs.billingCity;
|
|
|
+ defaultValues.billingPostcode = bs.billingPostcode;
|
|
|
+ defaultValues.billingPhoneNumber = bs.billingPhoneNumber;
|
|
|
+ // defaultValues.billingSameAsShipping = true;
|
|
|
+ }
|
|
|
+ if(shippingAddress) {
|
|
|
+ const ss = getShippingAddressFormData(shippingAddress);
|
|
|
+ defaultValues.shippingAddressId = ss.shippingAddressId;
|
|
|
+ defaultValues.shippingEmail = ss.shippingEmail;
|
|
|
+ defaultValues.shippingFirstName = ss.shippingFirstName;
|
|
|
+ defaultValues.shippingLastName = ss.shippingLastName;
|
|
|
+ defaultValues.shippingCompanyName = ss.shippingCompanyName;
|
|
|
+ defaultValues.shippingAddress = ss.shippingAddress;
|
|
|
+ defaultValues.shippingCountry = ss.shippingCountry;
|
|
|
+ defaultValues.shippingState = ss.shippingState;
|
|
|
+ defaultValues.shippingCity = ss.shippingCity;
|
|
|
+ defaultValues.shippingPostcode = ss.shippingPostcode;
|
|
|
+ defaultValues.shippingPhoneNumber = ss.shippingPhoneNumber;
|
|
|
+ }
|
|
|
+ if( defaultValues.billingEmail === defaultValues.shippingEmail &&
|
|
|
+ defaultValues.billingFirstName === defaultValues.shippingFirstName &&
|
|
|
+ defaultValues.billingLastName === defaultValues.shippingLastName &&
|
|
|
+ defaultValues.billingCompanyName === defaultValues.shippingCompanyName &&
|
|
|
+ defaultValues.billingAddress === defaultValues.shippingAddress &&
|
|
|
+ defaultValues.billingCountry === defaultValues.shippingCountry &&
|
|
|
+ defaultValues.billingState === defaultValues.shippingState &&
|
|
|
+ defaultValues.billingCity === defaultValues.shippingCity &&
|
|
|
+ defaultValues.billingPostcode === defaultValues.shippingPostcode &&
|
|
|
+ defaultValues.billingPhoneNumber === defaultValues.shippingPhoneNumber
|
|
|
+ ) {
|
|
|
+ defaultValues.billingSameAsShipping = true;
|
|
|
+ }
|
|
|
+ return defaultValues;
|
|
|
+}
|
|
|
/**
|
|
|
* 生成createCheckoutAddress接口的参数
|
|
|
*/
|
|
|
@@ -99,13 +211,17 @@ function generateSaveCheckoutAddressParam(formData: FullAddressFormData):CreateC
|
|
|
export default function CheckoutWrapper({
|
|
|
loginEmail,
|
|
|
countries,
|
|
|
+ cartDetailData,
|
|
|
}: {
|
|
|
loginEmail: string;
|
|
|
- countries: Country[],
|
|
|
+ countries: Country[];
|
|
|
+ cartDetailData: CartDetail;
|
|
|
}) {
|
|
|
|
|
|
+ const addressFormDefaultValues = getAddressFormDataFromCart(cartDetailData,loginEmail);
|
|
|
const dispatch = useAppDispatch();
|
|
|
- const { cartData } = useCartDetail();
|
|
|
+
|
|
|
+ const [cartData, setCartData] = useState<CartDetail>(cartDetailData);
|
|
|
const {saveCheckoutCart} = useSaveCheckoutCart();
|
|
|
|
|
|
const {
|
|
|
@@ -116,7 +232,8 @@ export default function CheckoutWrapper({
|
|
|
} = useCheckoutShippingMethod();
|
|
|
|
|
|
|
|
|
- const selectedPaymentMethod = cartData?.paymentMethod ?? 'paypal_smart_button';
|
|
|
+ const selectedPaymentMethod = cartData.paymentMethod || 'paypal_smart_button';
|
|
|
+ const selectedShippingRate = cartData.selectedShippingRate;
|
|
|
|
|
|
const {
|
|
|
data: paymentMethodDatas,
|
|
|
@@ -131,73 +248,32 @@ export default function CheckoutWrapper({
|
|
|
const methodShiippingRef = useRef<RefShippingMethodsHandle>(null);
|
|
|
const methodPaymentRef = useRef<RefPaymentMethodsHandle>(null);
|
|
|
|
|
|
+
|
|
|
|
|
|
// useForm() 只会在组件初始化时读取一次 defaultValues
|
|
|
const addressForm = useForm<FullAddressFormData>({
|
|
|
mode: "onBlur", // 或 "onChange"
|
|
|
reValidateMode: "onChange",
|
|
|
- defaultValues: {
|
|
|
- "shippingAddressId": "",
|
|
|
- "shippingEmail": loginEmail,
|
|
|
- "shippingFirstName": "",
|
|
|
- "shippingLastName": "jack",
|
|
|
- "shippingCompanyName": "",
|
|
|
- "shippingAddress": "",
|
|
|
- "shippingCountry": "US",
|
|
|
- "shippingState": "",
|
|
|
- "shippingCity": "",
|
|
|
- "shippingPostcode": "",
|
|
|
- "shippingPhoneNumber": "",
|
|
|
- "billingAddressId": "",
|
|
|
- "billingEmail": "",
|
|
|
- "billingFirstName": "",
|
|
|
- "billingLastName": "",
|
|
|
- "billingCompanyName": "",
|
|
|
- "billingAddress": "",
|
|
|
- "billingCountry": "US",
|
|
|
- "billingState": "",
|
|
|
- "billingCity": "",
|
|
|
- "billingPostcode": "",
|
|
|
- "billingPhoneNumber": "",
|
|
|
- "billingSameAsShipping": true
|
|
|
- }
|
|
|
+ defaultValues: addressFormDefaultValues
|
|
|
});
|
|
|
|
|
|
const [addressModalOpen, setAddressModalOpen] = useState(false);
|
|
|
- const [loadingAddress, setLoadingAddress] = useState(true); // 初始加载地址数据时的loading状态
|
|
|
|
|
|
- const serverShippingAddress = useRef<ShipAddressFormData | null>(null);
|
|
|
- const serverBillingAddress = useRef<BillAddressFormData | null>(null);
|
|
|
|
|
|
const [addressSaving, setAddressSaving] = useState(false); // 保存地址时的loading状态
|
|
|
|
|
|
- // 开发环境会执行两次 https://zh-hans.react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development
|
|
|
- useEffect(() => {
|
|
|
- getCheckoutAddress((shippingAddress,billingAddress)=> {
|
|
|
- addressForm.reset({
|
|
|
- ...shippingAddress,
|
|
|
- ...billingAddress,
|
|
|
- });
|
|
|
|
|
|
- serverShippingAddress.current = shippingAddress;
|
|
|
- serverBillingAddress.current = billingAddress;
|
|
|
-
|
|
|
- setLoadingAddress(false);
|
|
|
- }, ()=> {
|
|
|
- setLoadingAddress(false);
|
|
|
- });
|
|
|
- }, []);
|
|
|
|
|
|
|
|
|
const openAddressModal = () => {
|
|
|
setAddressModalOpen(true);
|
|
|
|
|
|
- if(serverShippingAddress.current && serverBillingAddress.current) {
|
|
|
+ if(cartData.billingAddress && cartData.shippingAddress) {
|
|
|
addressForm.reset({
|
|
|
- ...serverShippingAddress.current,
|
|
|
- ...serverBillingAddress.current,
|
|
|
+ ...getAddressFormDataFromCart(cartData)
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
|
|
|
};
|
|
|
const closeAddressModal = (e:boolean) => {
|
|
|
@@ -217,8 +293,8 @@ export default function CheckoutWrapper({
|
|
|
const res = await saveCheckoutAddress(saveAddressParam);
|
|
|
console.log('CREATE_CHECKOUT_ADDRESS res ====== ',res);
|
|
|
// 地址保存成功后重新获取运输方式和支付方式
|
|
|
- getShippingMethod();
|
|
|
- getPaymentMethod();
|
|
|
+ await getShippingMethod();
|
|
|
+ await getPaymentMethod();
|
|
|
|
|
|
// 保存完地址之后还要重新请求地址,把保存后的地址id同步到表单里;
|
|
|
const queryAddressRes = await getCheckoutAddress();
|
|
|
@@ -230,12 +306,17 @@ export default function CheckoutWrapper({
|
|
|
defaultValue: queryAddressRes.billingAddress.billingAddressId
|
|
|
});
|
|
|
|
|
|
- serverShippingAddress.current = queryAddressRes.shippingAddress;
|
|
|
- serverBillingAddress.current = queryAddressRes.billingAddress;
|
|
|
+
|
|
|
// 同步地址到购物车详情
|
|
|
+ const newBillingAddress = billingAddressToCartAddress(queryAddressRes.billingAddress);
|
|
|
+ const newShippingAddress = shippingAddressToCartAddress(queryAddressRes.shippingAddress);
|
|
|
dispatch(updateCart({
|
|
|
- billingAddress: billingAddressToCartAddress(queryAddressRes.billingAddress),
|
|
|
- shippingAddress: shippingAddressToCartAddress(queryAddressRes.shippingAddress)
|
|
|
+ billingAddress: newBillingAddress,
|
|
|
+ shippingAddress: newShippingAddress
|
|
|
+ }));
|
|
|
+ setCartData(Object.assign({...cartData},{
|
|
|
+ billingAddress: {...newBillingAddress},
|
|
|
+ shippingAddress: {...newShippingAddress}
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
@@ -252,7 +333,7 @@ export default function CheckoutWrapper({
|
|
|
};
|
|
|
|
|
|
|
|
|
- const handlePaymentMethodChange = async (method: string,title: string) => {
|
|
|
+ const handlePaymentMethodChange = async (method: string) => {
|
|
|
let shippingMethod = '-1';
|
|
|
if(methodShiippingRef.current) {
|
|
|
shippingMethod = methodShiippingRef.current.getSelectShipMethod();
|
|
|
@@ -268,24 +349,12 @@ export default function CheckoutWrapper({
|
|
|
if(saveRes.data) {
|
|
|
const newCartDetail = formatCartDetail(saveRes.data);
|
|
|
dispatch(updateCart(newCartDetail));
|
|
|
+ setCartData({...newCartDetail});
|
|
|
}
|
|
|
} else {
|
|
|
showToast(saveRes.msg, 'danger');
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- const res = await savePaymentMethod({ paymentMethod: method });
|
|
|
- console.log('savePaymentMethod res ====== ',res);
|
|
|
- if(!res.error) {
|
|
|
- // 更新paymentMethod paymentMethodTitle
|
|
|
- dispatch(updateCart({
|
|
|
- paymentMethod: method,
|
|
|
- paymentMethodTitle: title
|
|
|
- }));
|
|
|
- } else {
|
|
|
- showToast(res.msg, 'danger');
|
|
|
- }
|
|
|
- */
|
|
|
};
|
|
|
const handleShippingMethodChange = async (method: string) => {
|
|
|
overlayLoading.start();
|
|
|
@@ -299,21 +368,14 @@ export default function CheckoutWrapper({
|
|
|
if(saveRes.data) {
|
|
|
const newCartDetail = formatCartDetail(saveRes.data);
|
|
|
dispatch(updateCart(newCartDetail));
|
|
|
+ setCartData({...newCartDetail});
|
|
|
}
|
|
|
// 保存成功之后需要重新获取支付方式
|
|
|
getPaymentMethod();
|
|
|
} else {
|
|
|
showToast(saveRes.msg, 'danger');
|
|
|
}
|
|
|
- /*
|
|
|
- const res = await saveShippingMethod({ shippingMethod: method });
|
|
|
- if(!res.error) {
|
|
|
- // 保存成功之后需要重新获取购物车详情和支付方式
|
|
|
- getCartDetail();
|
|
|
- getPaymentMethod();
|
|
|
- } else {
|
|
|
- showToast(res.msg, 'danger');
|
|
|
- }*/
|
|
|
+
|
|
|
};
|
|
|
|
|
|
// 下单
|
|
|
@@ -354,7 +416,7 @@ export default function CheckoutWrapper({
|
|
|
}
|
|
|
|
|
|
//如果购物车详情没有保存过支付方式,则需要保存支付方式
|
|
|
- if(cartData?.paymentMethod === null) {
|
|
|
+ if(cartData.paymentMethod === null) {
|
|
|
const pmethod = methodPaymentRef?.current.getSelectPaymentMethod();
|
|
|
const saveRes = await saveCheckoutCart({
|
|
|
shippingMethod: '-1',
|
|
|
@@ -365,6 +427,7 @@ export default function CheckoutWrapper({
|
|
|
if(saveRes.data) {
|
|
|
const newCartDetail = formatCartDetail(saveRes.data);
|
|
|
dispatch(updateCart(newCartDetail));
|
|
|
+ setCartData({...newCartDetail});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -397,13 +460,16 @@ export default function CheckoutWrapper({
|
|
|
<section className="w-full">
|
|
|
<div>
|
|
|
{/* <button className="w-25 h-8 bg-amber-500 flex items-center justify-center" onClick={tt}>test</button> */}
|
|
|
- {loadingAddress ?
|
|
|
+ {/* {loadingAddress ?
|
|
|
<AddressResultDisplayLoading />
|
|
|
:
|
|
|
- <AddressResultDisplay shippingAddress={cartData?.shippingAddress ?? null}
|
|
|
+ <AddressResultDisplay shippingAddress={cartData.shippingAddress || null}
|
|
|
onAddressModalOpenClick={openAddressModal}
|
|
|
/>
|
|
|
- }
|
|
|
+ } */}
|
|
|
+ <AddressResultDisplay shippingAddress={cartData.shippingAddress || null}
|
|
|
+ onAddressModalOpenClick={openAddressModal}
|
|
|
+ />
|
|
|
<CommonModal
|
|
|
isOpen={addressModalOpen}
|
|
|
onClose={closeAddressModal}
|
|
|
@@ -451,6 +517,7 @@ export default function CheckoutWrapper({
|
|
|
ref={methodShiippingRef}
|
|
|
shipMethods={shippingMethodDatas}
|
|
|
errorMsg={shippingMethodError}
|
|
|
+ selectedShippingRate={selectedShippingRate}
|
|
|
onShipMethodChange={handleShippingMethodChange}
|
|
|
/>
|
|
|
}
|
|
|
@@ -466,18 +533,23 @@ export default function CheckoutWrapper({
|
|
|
ref={methodPaymentRef}
|
|
|
errorMsg={paymentMethodError}
|
|
|
paymentMethods={paymentMethodDatas}
|
|
|
+ selectedPaymentMethod={selectedPaymentMethod}
|
|
|
onPaymentMethodChange={handlePaymentMethodChange}
|
|
|
/>
|
|
|
}
|
|
|
|
|
|
</div>
|
|
|
- <div className="mt-3 box-border px-4">
|
|
|
+ <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">
|
|
|
- <CheckoutPlaceOrder
|
|
|
- paymentMethod={selectedPaymentMethod}
|
|
|
- clickPlaceOrder={handlePlaceOrder}
|
|
|
- />
|
|
|
+ { paymentMethodLoading ?
|
|
|
+ <LoadingCheckoutPlaceOrder />
|
|
|
+ :
|
|
|
+ <CheckoutPlaceOrder
|
|
|
+ paymentMethod={selectedPaymentMethod}
|
|
|
+ clickPlaceOrder={handlePlaceOrder}
|
|
|
+ />
|
|
|
+ }
|
|
|
</div>
|
|
|
</div>
|
|
|
|