Преглед изворни кода

货币切换组件优化;结账页地址板块优化;LyDropDown组件优化

fogwind пре 2 дана
родитељ
комит
026f3aacf4

+ 73 - 55
src/app/(checkout)/checkout/_components/CheckoutAddress/BillingAddressCheckout.tsx

@@ -26,6 +26,7 @@ import Select from "@/components/theme/ui/Select";
 import PhoneNumberInput from "@/components/theme/ui/PhoneNumberInput/PhoneNumberInput";
 import { LoadingSpinner } from "@components/common/LoadingSpinner";
 import {LyDropDown} from "@/components/theme/ui/LyDropDown";
+import MyAddressListTrigger from "./MyAddressListTrigger";
 
 export default function BillingAddressCheckout ({
     noAddress,
@@ -190,27 +191,71 @@ export default function BillingAddressCheckout ({
         
     },[selectedCountryCode,hasUserSelectedPhoneCode,getValues,setValue]);
 
-
-    const showMyAddressList = () => {
-        setShowDropDown(true);
+    /** 这个函数既要控制表单的显示隐藏还要控制地址列表的显示隐藏 
+     * 游客状态没有地址列表:
+     *     如果noAddress=true,购物车没有地址信息,不执行任何逻辑
+     *     如果noAddress=false,购物车里有地址信息,控制地址列表的显示隐藏,地址列表里有+New选项
+     * 
+     * 登录状态:
+     * 如果有地址列表,控制地址列表的显示隐藏,地址列表里有+New选项
+     * 如果没有地址列表:
+     *     如果noAddress=true, 购物车里没有地址信息,不执行任何逻辑
+     *     如果noAddress=false, 购物车里有地址信息,控制地址列表的显示隐藏,地址列表里有+New选项
+     *  
+    */
+    const myAddressListToggle = () => {
+        if(isGuest) { // 游客
+            if(!noAddress) { // 有地址
+                setShowDropDown(!showDropDown);
+            }
+        } else { // 登录用户
+            if(customerAddressList.length > 0) {
+                setShowDropDown(!showDropDown);
+            } else {
+                if(!noAddress) { 
+                    setShowDropDown(!showDropDown);
+                }
+            }
+        }
     };
     const closeMyaddressList = useCallback(() => {
         setShowDropDown(false);
     },[]);
 
     // 从地址列表选择地址
-    const selectAddress = (param: CustomerAddressItem | 'edit') => {
-        if(param === 'edit') {
+    const selectAddress = (param: CustomerAddressItem | 'new') => {
+        if(param === 'new') {
+            setValue('billingFirstName','');
+            setValue('billingLastName','');
+            setValue('billingAddress','');
+            setValue('billingCountry','US');
+            setValue('billingState','');
+            setValue('billingPostcode','');
+            setValue('billingCity','');
+            setValue('billingPhoneNumber','');
             if(!showFormField) onShowFormFieldChange(true);
         } else {
+            // 用户地址中,state字段有的是全称,有的是缩写,如何处理
+            // 对于有州列表的,拿state字段遍历州列表,分别对比全称和缩写,有一项相等,则填入缩写;如果没有找到匹配的,让用户自己选填
+            // 这就牵涉到一个问题,用户从地址列表中选地址的时候,还要显示出来表单,防止出现state字段校验不通过的情况;
+            if(statesOptions.length) {
+                const paramState = statesOptions.find((state) => {
+                    return state.label === param.state || state.value === param.state;
+                });
+                if(paramState) {
+                    setValue('billingState',paramState.value);
+                } else {
+                    setValue('billingState',param.state);
+                }
+            }
             setValue('billingFirstName',param.firstName);
             setValue('billingLastName',param.lastName);
             setValue('billingAddress',param.address);
             setValue('billingCountry',param.country);
-            setValue('billingState',param.state);
             setValue('billingPostcode',param.postcode);
             setValue('billingCity',param.city);
             setValue('billingPhoneNumber',param.phone);
+            if(!showFormField) onShowFormFieldChange(true);
         }
         closeMyaddressList();
     };
@@ -238,53 +283,30 @@ export default function BillingAddressCheckout ({
             <div className={clsx("w-full mt-4",{
                 "hidden": billingSameAsShipping,
             })}>
-                {noAddress ? 
-                    <div onClick={showMyAddressList}
-                        className="box-border w-full h-9 justify-between flex items-center px-4 relative bg-[url(/image/address-bg.webp)] bg-position-[0_-70%] bg-size-[100%_auto]"
-                    >
-                        <span className="text-ly-12">+New Shipping Address</span>
-                        {!isGuest && 
-                            <button className="flex-none" title="change address" type="button">
-                                <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="16" y="0" width="16" height="16" transform="rotate(90 16 0)"   fill="#FFFFFF" fillOpacity="0"></rect><path    stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M11.7295 6.32028L7.62964 10.4201L3.52978 6.32028"></path></svg>
-                            </button>
-                        }
-                    </div>
-                : 
-                    <div onClick={showMyAddressList}
-                        className="w-full box-border px-3.75 bg-[url(/image/address-bg.webp)] bg-position-[0_-84%] bg-size-[100%_auto]"
-                    >
-                        <div className="border-b-1 flex h-11.25 items-center justify-between">
-                            <p className="text-ly-13 font-medium">
-                                {firstName} {lastName}
-                                <span className="border-r border-ly-gray h-3.5 mx-2"></span> 
-                                {phoneNumber}
-                            </p>
-                            {!isGuest && 
-                                <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="16" y="0" width="16" height="16" transform="rotate(90 16 0)"   fill="#FFFFFF" fillOpacity="0"></rect><path    stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M11.7295 6.32028L7.62964 10.4201L3.52978 6.32028"></path></svg>
-                            }
-                        </div>
-                        <div className="flex items-center h-10">
-                            <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" fill="none">
-                                <path stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round"  d="M6.01652 15.917C4.48522 16.3764 3.53809 17.0111 3.53809 17.712C3.53809 19.1141 7.32661 20.2507 12 20.2507C16.6734 20.2507 20.4619 19.1141 20.4619 17.712C20.4619 17.0111 19.5148 16.3764 17.9835 15.917"></path>
-                                <path d="M12.0002 16.8657C12.0002 16.8657 17.5005 13.271 17.5005 9.11522C17.5005 6.15182 15.0379 3.74951 12.0002 3.74951C8.96254 3.74951 6.5 6.15182 6.5 9.11522C6.5 13.271 12.0002 16.8657 12.0002 16.8657Z" stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round"  ></path>
-                                <path d="M11.9983 11.3653C13.1666 11.3653 14.1138 10.4181 14.1138 9.24979C14.1138 8.08144 13.1666 7.13428 11.9983 7.13428C10.83 7.13428 9.88281 8.08144 9.88281 9.24979C9.88281 10.4181 10.83 11.3653 11.9983 11.3653Z" stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round"  ></path>
-                            </svg>
-                            <span className="text-ly-12 ml-2.5">
-                                {streetAddress}, 
-                                {city}, 
-                                {stateProvince}, 
-                                {postCode}, 
-                                {selectedCountryCode}
-                            </span>
-                        </div>
-                    </div>  
-                }
                 <LyDropDown
                     showDropDown={showDropDown}
                     onClose={closeMyaddressList}
+                    trigger={
+                        <MyAddressListTrigger 
+                            noAddress={noAddress}
+                            isGuest={isGuest}
+                            hasAddressList={customerAddressList.length > 0}
+                            addressInfo={{
+                                firstName,
+                                lastName,
+                                phoneNumber,
+                                streetAddress,
+                                city,
+                                stateProvince,
+                                postCode,
+                                countryCode: selectedCountryCode
+                            }}
+                            clickTrigger={myAddressListToggle}
+                        />                
+                    }
                 >
-                    <div className="w-full p-3 text-ly-13 font-medium" key={'edit'} onClick={() => {selectAddress('edit')}}>
-                        Edit Address
+                    <div className="w-full p-3 text-ly-13 font-medium" key={'new'} onClick={() => {selectAddress('new')}}>
+                        + New Billing Address
                     </div>
                     {customerAddressList.map((item) => {
                         return (
@@ -308,13 +330,9 @@ export default function BillingAddressCheckout ({
             </div> 
 
 
-            <div className={clsx("box-border w-full mt-4",{
-                    "hidden": (!showFormField && !noAddress) || billingSameAsShipping
-                })}
+            <div className={clsx("box-border w-full mt-4", (!showFormField && !noAddress) || billingSameAsShipping ? "hidden" : "block")}
             >
-                <div className={clsx("w-full",{
-                    "hidden": !isGuest
-                })}>
+                <div className={clsx("w-full", !isGuest ? "hidden" : "block")}>
                     <label className="text-ly-12 block mb-4 font-semibold">
                         Email *
                     </label>

Разлика између датотеке није приказан због своје велике величине
+ 84 - 0
src/app/(checkout)/checkout/_components/CheckoutAddress/MyAddressListTrigger.tsx


+ 76 - 57
src/app/(checkout)/checkout/_components/CheckoutAddress/ShippingAddressCheckout.tsx

@@ -21,7 +21,7 @@ import Select from "@/components/theme/ui/Select";
 import PhoneNumberInput from "@/components/theme/ui/PhoneNumberInput/PhoneNumberInput";
 import { LoadingSpinner } from "@components/common/LoadingSpinner";
 import {LyDropDown} from "@/components/theme/ui/LyDropDown";
-
+import MyAddressListTrigger from "./MyAddressListTrigger";
 
 
 export default function ShippingAddressCheckout({
@@ -128,25 +128,70 @@ export default function ShippingAddressCheckout({
         
     },[selectedCountryCode,hasUserSelectedPhoneCode,getValues,setValue]);
 
-    const showMyAddressList = () => {
-        setShowDropDown(true);
+    /** 这个函数既要控制表单的显示隐藏还要控制地址列表的显示隐藏 
+     * 游客状态没有地址列表:
+     *     如果noAddress=true,购物车没有地址信息,不执行任何逻辑
+     *     如果noAddress=false,购物车里有地址信息,控制地址列表的显示隐藏,地址列表里有+New选项
+     * 
+     * 登录状态:
+     * 如果有地址列表,控制地址列表的显示隐藏,地址列表里有+New选项
+     * 如果没有地址列表:
+     *     如果noAddress=true, 购物车里没有地址信息,不执行任何逻辑
+     *     如果noAddress=false, 购物车里有地址信息,控制地址列表的显示隐藏,地址列表里有+New选项
+     *  
+    */
+    const myAddressListToggle = () => {
+        if(isGuest) { // 游客
+            if(!noAddress) { // 有地址
+                setShowDropDown(!showDropDown);
+            }
+        } else { // 登录用户
+            if(customerAddressList.length > 0) {
+                setShowDropDown(!showDropDown);
+            } else {
+                if(!noAddress) { 
+                    setShowDropDown(!showDropDown);
+                }
+            }
+        }
     };
     const closeMyaddressList = useCallback(() => {
         setShowDropDown(false);
     },[]);
     // 从地址列表选择地址
-    const selectAddress = (param: CustomerAddressItem | 'edit') => {
-        if(param === 'edit') {
+    const selectAddress = (param: CustomerAddressItem | 'new') => {
+        if(param === 'new') {
+            setValue('shippingFirstName','');
+            setValue('shippingLastName','');
+            setValue('shippingAddress','');
+            setValue('shippingCountry','US');
+            setValue('shippingState','');
+            setValue('shippingPostcode','');
+            setValue('shippingCity','');
+            setValue('shippingPhoneNumber','');
             if(!showFormField) onShowFormFieldChange(true);
         } else {
+            // 用户地址中,state字段有的是全称,有的是缩写,如何处理
+            // 对于有州列表的,拿state字段遍历州列表,分别对比全称和缩写,有一项相等,则填入缩写;如果没有找到匹配的,让用户自己选填
+            // 这就牵涉到一个问题,用户从地址列表中选地址的时候,还要显示出来表单,防止出现state字段校验不通过的情况;
+            if(statesOptions.length) {
+                const paramState = statesOptions.find((state) => {
+                    return state.label === param.state || state.value === param.state;
+                });
+                if(paramState) {
+                    setValue('shippingState',paramState.value);
+                } else {
+                    setValue('shippingState',param.state);
+                }
+            }
             setValue('shippingFirstName',param.firstName);
             setValue('shippingLastName',param.lastName);
             setValue('shippingAddress',param.address);
             setValue('shippingCountry',param.country);
-            setValue('shippingState',param.state);
             setValue('shippingPostcode',param.postcode);
             setValue('shippingCity',param.city);
             setValue('shippingPhoneNumber',param.phone);
+            if(!showFormField) onShowFormFieldChange(true);
         }
         closeMyaddressList();
     };
@@ -171,53 +216,31 @@ export default function ShippingAddressCheckout({
     return (<>
         
         <div className="w-full">
-            {noAddress ? 
-                <div onClick={showMyAddressList}
-                    className="box-border w-full h-9 justify-between flex items-center px-4 relative bg-[url(/image/address-bg.webp)] bg-position-[0_-70%] bg-size-[100%_auto]"
-                >
-                    <span className="text-ly-12">+New Shipping Address</span>
-                    {!isGuest && 
-                        <button className="flex-none" title="change address" type="button">
-                            <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="16" y="0" width="16" height="16" transform="rotate(90 16 0)"   fill="#FFFFFF" fillOpacity="0"></rect><path    stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M11.7295 6.32028L7.62964 10.4201L3.52978 6.32028"></path></svg>
-                        </button>
-                    }
-                </div>
-            : 
-                <div onClick={showMyAddressList}
-                    className="w-full box-border px-3.75 bg-[url(/image/address-bg.webp)] bg-position-[0_-84%] bg-size-[100%_auto]"
-                >
-                    <div className="border-b-1 flex h-11.25 items-center justify-between">
-                        <p className="text-ly-13 font-medium">
-                            {firstName} {lastName}
-                            <span className="border-r border-ly-gray h-3.5 mx-2"></span> 
-                            {phoneNumber}
-                        </p>
-                        {!isGuest && 
-                            <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" fill="none"><rect x="16" y="0" width="16" height="16" transform="rotate(90 16 0)"   fill="#FFFFFF" fillOpacity="0"></rect><path    stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M11.7295 6.32028L7.62964 10.4201L3.52978 6.32028"></path></svg>
-                        }
-                    </div>
-                    <div className="flex items-center h-10">
-                        <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" fill="none">
-                            <path stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round"  d="M6.01652 15.917C4.48522 16.3764 3.53809 17.0111 3.53809 17.712C3.53809 19.1141 7.32661 20.2507 12 20.2507C16.6734 20.2507 20.4619 19.1141 20.4619 17.712C20.4619 17.0111 19.5148 16.3764 17.9835 15.917"></path>
-                            <path d="M12.0002 16.8657C12.0002 16.8657 17.5005 13.271 17.5005 9.11522C17.5005 6.15182 15.0379 3.74951 12.0002 3.74951C8.96254 3.74951 6.5 6.15182 6.5 9.11522C6.5 13.271 12.0002 16.8657 12.0002 16.8657Z" stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round"  ></path>
-                            <path d="M11.9983 11.3653C13.1666 11.3653 14.1138 10.4181 14.1138 9.24979C14.1138 8.08144 13.1666 7.13428 11.9983 7.13428C10.83 7.13428 9.88281 8.08144 9.88281 9.24979C9.88281 10.4181 10.83 11.3653 11.9983 11.3653Z" stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round"  ></path>
-                        </svg>
-                        <span className="text-ly-12 ml-2.5">
-                            {streetAddress}, 
-                            {city}, 
-                            {stateProvince}, 
-                            {postCode}, 
-                            {selectedCountryCode}
-                        </span>
-                    </div>
-                </div>  
-            }
+
             <LyDropDown
                 showDropDown={showDropDown}
                 onClose={closeMyaddressList}
+                trigger={
+                    <MyAddressListTrigger 
+                        noAddress={noAddress}
+                        isGuest={isGuest}
+                        hasAddressList={customerAddressList.length > 0}
+                        addressInfo={{
+                            firstName,
+                            lastName,
+                            phoneNumber,
+                            streetAddress,
+                            city,
+                            stateProvince,
+                            postCode,
+                            countryCode: selectedCountryCode
+                        }}
+                        clickTrigger={myAddressListToggle}
+                    />
+                }
             >
-                <div className="w-full p-3 text-ly-13 font-medium" key={'edit'} onClick={() => {selectAddress('edit')}}>
-                    Edit Address
+                <div className="w-full p-3 text-ly-13 font-medium" key={'new'} onClick={() => {selectAddress('new')}}>
+                    + New Shipping Address
                 </div>
                 {customerAddressList.map((item) => {
                     return (
@@ -245,15 +268,11 @@ export default function ShippingAddressCheckout({
             Select a shipping address from your address book or enter a new address.
         </p>
         {/**
-         * 登录用户: noAddres=false and showFormField = false 时 隐藏;  noAddres=true 显示
-         * 游客: noAddres=false and showFormField = false 时 隐藏; noAddres=true 显示
+         * 登录用户: noAddres=false(有地址) and showFormField = false 时 隐藏;  noAddres=true 显示
+         * 游客: noAddres=false(有地址) and showFormField = false 时 隐藏; noAddres=true 显示
          */}
-        <div className={clsx("box-border w-full", {
-            "hidden": !showFormField && !noAddress
-        })}>
-            <div className={clsx("w-full",{
-                "hidden": !isGuest
-            })}>
+        <div className={clsx("box-border w-full", !showFormField && !noAddress ? "hidden" : "block")}>
+            <div className={clsx("w-full",isGuest ? "block" : "hidden")}>
                 <label className="text-ly-12 block mb-4 font-semibold">
                     Email *
                 </label>

Разлика између датотеке није приказан због своје велике величине
+ 42 - 66
src/components/common/CurrencySwitch/CurrencySwitch.tsx


+ 0 - 154
src/components/home/HomeImageBanner.tsx

@@ -1,154 +0,0 @@
-"use client";
-
-import { useRouter } from 'next/navigation';
-import { Swiper, SwiperSlide } from 'swiper/react';
-import {CurrencySwitch} from "@/components/common/CurrencySwitch/CurrencySwitch";
-import makeClient from "@/lib/ApolloClientBrowser";
-import { GET_CART_ITEM,GET_FILTER_ATTRIBUTES,CREATE_APPLY_COUPON, GET_COUNTRY_STATES} from "@/graphql";
-import { useMutation, useLazyQuery, useQuery } from "@apollo/client/react";
-import {handleApolloBusinessError} from "@/lib/ApolloErrorHandler";
-import { useCustomToast } from "@/utils/hooks/useToast";
-// interface ImageCarouselProps {
-//     options: {
-//         images: {
-//             image: string;
-//             link: string;
-//             title?: string;
-//         }[];
-//     };
-// }
-export default function HomeImageBanner() {
-  const router = useRouter();
-  const { showToast } = useCustomToast();
-  const apolloClient = makeClient();
-  const res = useQuery(GET_COUNTRY_STATES, {
-          variables: {
-              countryId: 1000
-          }
-      });
-      console.log('query state --- res', res);
-  const ttt = async () => {
-    try {
-      const res = await apolloClient.mutate({
-        mutation: GET_CART_ITEM,
-        fetchPolicy: 'network-only', // 按需调整
-      });
-      console.log('----------',res);
-    } catch(error) {
-      console.log('ttt----------',error);
-      handleApolloBusinessError(error,(err) => {
-          showToast(err.message, "danger");
-      });
-    }  
-  }
-  // 76|nlq9qGztR7qmSS72Kal56NCjhRRVrLCeVOdZdLLYa2c769e9
-const [getContent] = useLazyQuery(GET_FILTER_ATTRIBUTES,{
-        fetchPolicy: 'network-only'
-    });
-
-  const testLazyQuery = async () => { 
-      try {
-            const result = await getContent();
-            console.log('lazy query res---', result);
-      } catch(err) {
-          console.log('lazy query ---- ', err);
-      }
-  }
-
-    // useMutation
-    
-
-
-    const [mutateAsync] = useMutation(
-        GET_CART_ITEM,
-        {
-          onCompleted: (res) => {
-            console.log('useMutation onCompleted res ----- 0',res);
-          },
-    
-          onError: (err) => {
-            console.log('useMutation onCompleted err ----- 0',err);
-          },
-        },
-      );
-
-
-    const testMutation = async () => { 
-        
-            const res = await mutateAsync();
-        console.log('testMutation ---',res)
-        
-    };
-    const testFilter= () => {
-            return apolloClient.query({
-                query: GET_FILTER_ATTRIBUTES,
-                fetchPolicy: "no-cache",
-                context: {
-                    fetchOptions: {
-                        cache: 'no-store',
-                    },
-            
-                },
-                // variables: {
-                //     orderId: Number(orderid)
-                // }
-            }).then((res) => {
-                
-                console.log('testFilter res ---- ',res);
-            
-            
-            }).catch((err) => {
-                console.error('testFilter error ---- ',err);
-                handleApolloBusinessError(err,(error) => {
-          showToast(error.message, "danger");
-      });
-            });
-        };
-    
-        const testApplyCoupon = async () => { 
-            try {
-                await apolloClient.mutate({
-                    mutation: CREATE_APPLY_COUPON,
-                    variables: {
-                        couponCode: 'BIRTHDAY20'
-                    },
-                    fetchPolicy: 'network-only', // 按需调整
-                });
-            } catch (err) {
-                console.log('testApplyCoupon error ---- ',err);
-            }
-        };
-
-
-        const toggleLoginModal = () => {
-          // openLoginModal();
-          router.refresh();
-        };
-  
-  return (
-    <>
-    <p>
-      <button onClick={ttt}>get cart detail</button>
-    </p>
-
-    <p><button onClick={testLazyQuery}>testLazyQuery</button></p>
-    <p><button onClick={testMutation}>testMutation</button></p>
-    <p><button onClick={testFilter}>testFilter</button></p>
-    <p><button onClick={testApplyCoupon}>testApplyCoupon</button></p>
-    <Swiper
-      spaceBetween={50}
-      slidesPerView={3}
-      onSlideChange={() => console.log('slide change')}
-      onSwiper={(swiper) => console.log(swiper)}
-    >
-      <SwiperSlide>Slide 1</SwiperSlide>
-      <SwiperSlide>Slide 2</SwiperSlide>
-      <SwiperSlide>Slide 3</SwiperSlide>
-      <SwiperSlide>Slide 4</SwiperSlide>
-    </Swiper>
-    <CurrencySwitch/>
-
-    <p><button onClick={() => toggleLoginModal()}>show Login Modal</button></p>
-    </>
-  )
-}

+ 2 - 2
src/components/layout/navbar/MobileMenu.tsx

@@ -32,7 +32,7 @@ export default function MobileMenu({ menu, isOpen, onClose,isGuest }: MobileMenu
   const activeMainMenu = menu.find((item) => item._id === activeMainId);
   // 当前一级下面全部二级菜单列表
   const subMenuList = activeMainMenu?.children?.edges?.map((e) => e.node) ?? [];
-  console.log("menu------------cscscs",menu);
+
   
   // 切换右侧二级菜单展开/收起
   const toggleSubExpand = (subId: number) => {
@@ -267,7 +267,7 @@ export default function MobileMenu({ menu, isOpen, onClose,isGuest }: MobileMenu
                             <svg xmlns="http://www.w3.org/2000/svg"  width="24" height="24" viewBox="0 0 24 24" fill="none" 
                             className={`transition-transform duration-300 ${isOpen ? "rotate-0" : "rotate-180"}`}
                             >
-                             <path    stroke="rgba(0, 0, 0, 1)" stroke-width="1.5" stroke-linejoin="round" stroke-linecap="square"  d="M18 15L12 9L6 15"></path>
+                             <path    stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="square"  d="M18 15L12 9L6 15"></path>
                             </svg>
                            </div>
                        

+ 1 - 1
src/components/layout/navbar/index.tsx

@@ -46,7 +46,7 @@ export default async function Navbar() {
       query: GET_TREEFRONT_MENUS,
       takeAuthorization: false,
     });
-    console.log('GetTreefrontMenusResult --- ',menudata)
+    // console.log('GetTreefrontMenusResult --- ',menudata)
     const menudatas =menudata? menudata.treefrontMenus:[];
 
   return (

+ 43 - 20
src/components/theme/ui/LyDropDown.tsx

@@ -6,38 +6,61 @@ import clsx from "clsx";
 
 export function LyDropDown({
     showDropDown,
+    trigger,
     children,
-    onClose
+    onClose,
+    className,
+    listClassName
 }: {
     showDropDown: boolean;
+    trigger: ReactNode;
     children: ReactNode;
     onClose: () => void;
+    className?: string;
+    listClassName?: string;
 }) {
     const listRef = useRef<HTMLDivElement>(null);
     const rootRef = useRef<HTMLDivElement>(null);
-    const [listPosition, setListPosition] = useState({
+    const triggerRef = useRef<HTMLDivElement>(null);
+    const [listPosition, setListPosition] = useState<React.CSSProperties>({
+        position: 'absolute',
         top: '0',
+        left: '0',
         transform: 'translate3d(0, 0%, 0)', 
     });
 
     useLayoutEffect(() => {
         if (listRef.current && rootRef.current && showDropDown) {
-            const { height } = listRef.current.getBoundingClientRect();
+            const { height, width } = listRef.current.getBoundingClientRect();
             // setListHeight(height);
             console.log('Measured tooltip height: ' + height);
 
-            const triggerRect = rootRef.current.getBoundingClientRect();
-            if(triggerRect.bottom + height > window.innerHeight) { // 显示在上方
-                setListPosition({
-                    top: '0',
-                    transform: 'translate3d(0, -100%, 0)',
-                });
+            // 标准模式下视口宽度和高度
+            const viewPortWidth = document.documentElement.clientWidth;
+            const viewPortHeight = document.documentElement.clientHeight;
+            const rootRect = rootRef.current.getBoundingClientRect();
+            let top = '0';
+            let left = '0';
+            let transform = 'translate3d(0, 0%, 0)';
+            if(rootRect.bottom + height > viewPortHeight) { // 显示在上方
+                top = '0';
+                transform = 'translate3d(0, -100%, 0)';
             } else { // 显示在下方
-                setListPosition({
-                    top: `${triggerRect.height}px`,
-                    transform: `translate3d(0, 0%, 0)`
-                });
+                top = `${rootRect.height}px`;
+                transform = 'translate3d(0, 0%, 0)';
+            }
+            if(rootRect.left + width > viewPortWidth) {
+                left = `-${rootRect.left + width - viewPortWidth}px`;
+            } else {
+                left = '0';
             }
+            setListPosition((pre) => {
+                return Object.assign({...pre},{
+                    top,
+                    transform,
+                    left
+                });
+            });
             
         }
     }, [showDropDown]);
@@ -53,10 +76,9 @@ export function LyDropDown({
 
             const target = event.target as Node;
 
-            if (
-                rootRef.current &&
-                !rootRef.current.contains(target)
-            ) {
+            if (triggerRef?.current?.contains(target)) return;
+
+            if (rootRef.current && !rootRef.current.contains(target)) {
                 onClose();
             }
         }
@@ -84,10 +106,11 @@ export function LyDropDown({
 
     return (
         <>
-            <div className="w-full relative" ref={rootRef}>
+            <div className={clsx("relative", className ? className : "w-full")} ref={rootRef}>
 
-                <div ref={listRef} className={clsx(
-                    "absolute w-full max-h-48 overflow-auto bg-white ly-thin-shadow border border-ly-gray rounded-md z-1",
+                <div className="w-full" ref={triggerRef}>{trigger}</div>
+                <div ref={listRef} className={clsx("absolute max-h-48 overflow-y-auto bg-white ly-thin-shadow border border-ly-gray rounded-md z-1",
+                    listClassName ? listClassName : "w-full",
                     showDropDown  ? "visible pointer-events-auto" : "invisible pointer-events-none"
                 )}
                     onClick={(e) => { e.stopPropagation(); }}