Просмотр исходного кода

结账页地址板块 -- v2 切换国家和电话区号同步问题

fogwind 4 дней назад
Родитель
Сommit
6f4e919a50

+ 10 - 6
src/app/(checkout)/checkout/_components/BillingAddressCheckout.tsx

@@ -1,6 +1,6 @@
 "use client";
 
-import { useMemo, useEffect } from "react";
+import { useMemo, useState, useEffect } from "react";
 import { useQuery } from "@apollo/client/react";
 import clsx from "clsx";
 import { 
@@ -120,14 +120,17 @@ export default function BillingAddressCheckout ({
         }));
     }
 
-    // @todo 国家变更后 state字段的值需要清空
+   
+    // 是否用户手动选择过区号
+    const [hasUserSelectedPhoneCode, setHasUserSelectedPhoneCode] = useState(false);
+
     // 选择国家时同步电话区号
     useEffect(() => {
         const preBillingPhoneNum = getValues('billingPhoneNumber');
         const regPhoneCode = IS_VALID_PHONECODE;
     
-        if(preBillingPhoneNum) {
-            const newPhoneCode = getPhoneCodeBycountryCode(selectedCountryCode) || '+1';
+        if(preBillingPhoneNum && !hasUserSelectedPhoneCode) {
+            const newPhoneCode = getPhoneCodeBycountryCode(selectedCountryCode);
             const codePart = regPhoneCode.exec(preBillingPhoneNum);
             let phone = preBillingPhoneNum;
             if(codePart) {
@@ -136,7 +139,7 @@ export default function BillingAddressCheckout ({
             setValue('billingPhoneNumber',formatFinalPhoneValue(newPhoneCode, phone))
         }
         
-    },[selectedCountryCode,getValues,setValue]);
+    },[selectedCountryCode,hasUserSelectedPhoneCode,getValues,setValue]);
 
 
 
@@ -336,7 +339,8 @@ export default function BillingAddressCheckout ({
                                     ref={field.ref}
                                     error={fieldState.error?.message}
                                     countryCode={selectedCountryCode}
-                                    phoneCodeChange={(e) => setValue("billingCountry", e)}
+                                    hasUserSelectedPhoneCode={hasUserSelectedPhoneCode}
+                                    onHasUserSelectedPhoneCode={() => setHasUserSelectedPhoneCode(true)}
                                 />
                             );
                         }}

+ 5 - 2
src/app/(checkout)/checkout/_components/CheckoutWrapper.tsx

@@ -116,7 +116,10 @@ export default function CheckoutWrapper({
 
 
     // useForm() 只会在组件初始化时读取一次 defaultValues
-    const addressForm = useForm<FullAddressFormData>();
+    const addressForm = useForm<FullAddressFormData>({
+        mode: "onBlur",          // 或 "onChange"
+        reValidateMode: "onChange", 
+    });
 
     const [addressModalOpen, setAddressModalOpen] = useState(false);
     const [loadingData, setLoadingData] = useState(true);
@@ -231,7 +234,7 @@ export default function CheckoutWrapper({
         addressForm.reset();
     };
     const addressFormOnSubmit = async (formData: FullAddressFormData) => { 
-        // console.log('addressFormOnSubmit ---- ',formData);
+        // console.log('addressFormOnSubmit ---- ',formData); return;
         // 保存完地址之后还要重新请求地址,把保存后的地址id同步到表单里;还需要获取运输方式
 
         const saveAddressParam = generateSaveCheckoutAddressParam(formData);

+ 10 - 5
src/app/(checkout)/checkout/_components/ShippingAddressCheckout.tsx

@@ -1,6 +1,6 @@
 "use client";
 
-import {useMemo,useEffect} from "react";
+import {useMemo,useEffect, useState} from "react";
 import { useQuery } from "@apollo/client/react";
 import { 
     useFormContext, 
@@ -65,14 +65,17 @@ export default function ShippingAddressCheckout ({
         }));
     }
 
+    // 是否用户手动选择过区号
+    const [hasUserSelectedPhoneCode, setHasUserSelectedPhoneCode] = useState(false);
+
     // 国家变更后 state字段的值需要清空
     // 选择国家时同步电话区号
     useEffect(() => {
         const preShippingPhoneNum = getValues('shippingPhoneNumber');
         const regPhoneCode = IS_VALID_PHONECODE;
     
-        if(preShippingPhoneNum) {
-            const newPhoneCode = getPhoneCodeBycountryCode(selectedCountryCode) || '+1';
+        if(preShippingPhoneNum && !hasUserSelectedPhoneCode) {
+            const newPhoneCode = getPhoneCodeBycountryCode(selectedCountryCode);
             const codePart = regPhoneCode.exec(preShippingPhoneNum);
             let phone = preShippingPhoneNum;
             if(codePart) {
@@ -81,7 +84,8 @@ export default function ShippingAddressCheckout ({
             setValue('shippingPhoneNumber',formatFinalPhoneValue(newPhoneCode, phone))
         }
         
-    },[selectedCountryCode,getValues,setValue]);
+    },[selectedCountryCode,hasUserSelectedPhoneCode,getValues,setValue]);
+
 
     return (
         <div className="box-border w-full">
@@ -258,7 +262,8 @@ export default function ShippingAddressCheckout ({
                                 ref={field.ref}
                                 error={fieldState.error?.message}
                                 countryCode={selectedCountryCode}
-                                phoneCodeChange={(e) => setValue("shippingCountry", e)}
+                                hasUserSelectedPhoneCode={hasUserSelectedPhoneCode}
+                                onHasUserSelectedPhoneCode={() => setHasUserSelectedPhoneCode(true)}
                             />
                         );
                     }}

+ 46 - 61
src/components/theme/ui/PhoneNumberInput/PhoneNumberInput.tsx

@@ -5,7 +5,8 @@ import Image from "next/image";
 import clsx from "clsx";
 import {
     COUNTRY_PHONECODE,
-    formatFinalPhoneValue
+    formatFinalPhoneValue,
+    getPhoneCodeBycountryCode
 } from "./phoneCodeMetaData";
 import { IS_VALID_PHONECODE } from "@utils/constants";
 
@@ -34,17 +35,7 @@ function parsePhoneValue(value: string|undefined) {
 /**
  * 受控组件
  */
-function PhoneNumberInput({
-    value,
-    placeholder,
-    onChange,
-    onBlur,
-    name,
-    error,
-    ref,
-    countryCode = "US",
-    phoneCodeChange
-}: {
+interface PhoneNumberInputProps {
     // 用于react-hook-form时,推荐使用useForm的 defaultValues 对整个表单设置默认值
     value?: string;
     placeholder: string;
@@ -54,9 +45,22 @@ function PhoneNumberInput({
     name: string;
     error?: string;
     ref?: React.Ref<HTMLInputElement>;
-    countryCode: string;
-    phoneCodeChange: (e: string) => void;
-}) {
+    countryCode: string;//父组件表单国家字段
+    onHasUserSelectedPhoneCode: () => void;
+    hasUserSelectedPhoneCode: boolean;
+}
+function PhoneNumberInput({
+    value,
+    placeholder,
+    onChange,
+    onBlur,
+    name,
+    error,
+    ref,
+    countryCode,
+    onHasUserSelectedPhoneCode,
+    hasUserSelectedPhoneCode
+}: PhoneNumberInputProps) {
     // const DEFAULT_COUNTRY_CODE = "US";
     const phoneCodeList = COUNTRY_PHONECODE;
 
@@ -64,45 +68,18 @@ function PhoneNumberInput({
         return parsePhoneValue(value);
     }, [value]);
 
-    
-
-    // const [finalPhone, setFinalPhone] = useState("");
-    // const [phoneCode, setPhoneCode] = useState(DEFAULT_PHONE_CODE);
-    // const [phoneNumber, setPhoneNumber] = useState("");
-
-    // useEffect(() => {
-    //     // +1-345 / +44
-    //     if(value) {
-    //         const regPhoneCode = IS_VALID_PHONECODE;
-    //         const codePart = regPhoneCode.exec(value);
-    //         let code = DEFAULT_PHONE_CODE;
-    //         let phone = '';
-           
-            
-    //         if(codePart) {
-    //             code = codePart[0].trim() || DEFAULT_PHONE_CODE;
-    //             phone = value.replace(codePart[0], '');
-    //         } else {
-    //             phone = value;
-    //         }
-    //         // const finalPhoneValue = formatFinalPhoneValue(code, phone);
-    //         setPhoneCode(code);
-    //         setPhoneNumber(phone);
-    //         // setFinalPhone(finalPhoneValue);
-            
-    //     }
-        
-    // }, [value]);
-
-
-    // let flagSvg = '';
-    // countryCode = DEFAULT_COUNTRY_CODE;
-    // if(phoneCode) {
-    //     countryCode = getCountryCodeByPhoneCode(phoneCode);
-    // }
-    const flagSvg = `/image/flags/4x3/${countryCode.toLowerCase()}.svg`;
 
+    const [selectedPhoneCode, setSelectedPhoneCode] = useState<string | null>(null);
+    const [selectedCountryForPhoneCode, setSelectedCountryForPhoneCode] = useState<string | null>(null);
     
+    const displayPhonecode = useMemo(() => {
+        return selectedPhoneCode ?? getPhoneCodeBycountryCode(countryCode);
+    },[selectedPhoneCode,countryCode]);
+    const displayCountryCode = useMemo(() => {
+        return selectedCountryForPhoneCode ?? countryCode;
+    }, [selectedCountryForPhoneCode,countryCode]);
+
+    ////////////////////////////////
     const rootRef = useRef<HTMLDivElement>(null);
     const [rootBounding, setRootBounding] = useState<{
         top: number;
@@ -155,20 +132,27 @@ function PhoneNumberInput({
         }
         setShowCodeList(!showCodeList);
     };
+    ///////////////////////////
 
-    const phoneCodeSelect = (phoneCode: string) => {
-        onChange(formatFinalPhoneValue(phoneCode, phoneNumber));
-        // setPhoneCode(phoneCode);
+    const phoneCodeSelect = (pCode: string, ccode: string) => {
+        onChange(formatFinalPhoneValue(pCode, phoneNumber));
+        setSelectedPhoneCode(pCode);
+        setSelectedCountryForPhoneCode(ccode);
+        
+        if(!hasUserSelectedPhoneCode) {
+            onHasUserSelectedPhoneCode(); // 标记为用户手动选择过
+        }
         setShowCodeList(false);
     };
 
     const phoneNumberChange = (value: string) => {
+
         onChange(formatFinalPhoneValue(phoneCode, value));
-        // setPhoneNumber(value);
+
     };
     const phoneNumberBlur = (value: string) => {
         onBlur(formatFinalPhoneValue(phoneCode, value));
-        // setPhoneNumber(value);
+
     };
     // const phoneNumberInput = (value: string) => {
     //     setPhoneNumber(value);
@@ -186,9 +170,10 @@ function PhoneNumberInput({
                     <div className="h-11.5 text-ly-12 flex items-center">
                         
                         <Image alt="china flag" width={24} height={18} className="w-6 h-4.5 mr-2"
-                            src={flagSvg}
+                            src={`/image/flags/4x3/${displayCountryCode.toLowerCase()}.svg`}
                         />
-                        {phoneCode}
+                        {/* {phoneCode} */}
+                        {displayPhonecode}
                     </div>
                 </div>
                 
@@ -214,8 +199,8 @@ function PhoneNumberInput({
                     {phoneCodeList.map((item) => {
                         return (<li className="text-ly-12 flex items-center h-8 gap-2" key={item.code} 
                             onClick={() => {
-                                phoneCodeSelect(item.phoneCode);
-                                phoneCodeChange(item.code);
+                                phoneCodeSelect(item.phoneCode, item.code);
+                                // phoneCodeChange(item.code);
                             }}
                         >
                             <Image alt="china flag" width={20} height={15} className="w-5 h-3.75"

+ 2 - 2
src/components/theme/ui/PhoneNumberInput/phoneCodeMetaData.ts

@@ -1449,11 +1449,11 @@ function formatFinalPhoneValue(phoneCode:string, phoneNum:string) {
 
 function getCountryCodeByPhoneCode(phoneCode: string) {
   const country = COUNTRY_PHONECODE.find((country) => country.phoneCode === phoneCode);
-  return country ? country.code : null;
+  return country ? country.code : 'US';
 }
 function getPhoneCodeBycountryCode(countryCode: string) {
   const country = COUNTRY_PHONECODE.find((country) => country.code === countryCode);
-  return country ? country.phoneCode : null;
+  return country ? country.phoneCode : '+1';
 }
 export {
     COUNTRY_PHONECODE,