瀏覽代碼

合并master

fogwind 2 周之前
父節點
當前提交
267938c74e
共有 39 個文件被更改,包括 851 次插入236 次删除
  1. 二進制
      public/image/account/202306141502.png
  2. 二進制
      public/image/account/202306141504.png
  3. 二進制
      public/image/account/202306141505.png
  4. 二進制
      public/image/account/202306141506.png
  5. 二進制
      public/image/account/202605201502.png
  6. 7 3
      src/app/(public)/customer/account/edit/page.tsx
  7. 214 0
      src/app/(public)/customer/account/mypoints/page.tsx
  8. 20 7
      src/app/(public)/customer/account/page.tsx
  9. 308 0
      src/app/(public)/customer/account/pointlist/page.tsx
  10. 5 5
      src/app/(public)/customer/address/new/page.tsx
  11. 2 2
      src/app/(public)/customer/address/page.tsx
  12. 3 5
      src/app/(public)/product/[...urlProduct]/page.tsx
  13. 8 9
      src/app/(public)/product/_components/ProductInformation.tsx
  14. 1 1
      src/app/(public)/product/_components/ProductMedia.tsx
  15. 1 1
      src/app/(public)/product/_components/review/ReviewDetail.tsx
  16. 5 5
      src/app/api/graphql/route.ts
  17. 7 7
      src/components/Portal.tsx
  18. 5 13
      src/components/cart/CartModal.tsx
  19. 9 8
      src/components/common/AddToCartModal/AddToCartModal.tsx
  20. 3 1
      src/components/common/AddToCartModal/AddToCartModalWrapper.tsx
  21. 2 2
      src/components/common/AddToCartModal/OpenAddToCartModalButton.tsx
  22. 1 1
      src/components/common/AddToCartModal/ProductOptionsInAddToCartModal.tsx
  23. 177 0
      src/components/customer/PointsRule.tsx
  24. 2 5
      src/components/home/CategoryCarousel.tsx
  25. 2 9
      src/components/home/ProductCarousel.tsx
  26. 0 1
      src/components/layout/navbar/MobileMenu.tsx
  27. 11 66
      src/components/theme/filters/SortOrder.tsx
  28. 1 1
      src/lib/ApolloClientBrowser.ts
  29. 1 1
      src/lib/ApolloClientServer.ts
  30. 3 46
      src/lib/graphql-fetch.ts
  31. 1 1
      src/lib/restApiClient.ts
  32. 1 1
      src/providers/ApolloWrapper.tsx
  33. 1 1
      src/store/slices/addToCartDialogSlice.ts
  34. 1 1
      src/utils/bagisto/index.ts
  35. 4 4
      src/utils/hooks/useAddToCart.ts
  36. 1 1
      src/utils/hooks/useCartDetail.ts
  37. 41 25
      src/utils/hooks/useGuestCartToken.ts
  38. 1 1
      src/utils/hooks/useMergeCart.ts
  39. 2 2
      src/utils/variantTools.ts

二進制
public/image/account/202306141502.png


二進制
public/image/account/202306141504.png


二進制
public/image/account/202306141505.png


二進制
public/image/account/202306141506.png


二進制
public/image/account/202605201502.png


+ 7 - 3
src/app/(public)/customer/account/edit/page.tsx

@@ -4,9 +4,9 @@ import { useState } from "react";
 import { useEffect } from "react";
 import {
   parseDate,
-  getLocalTimeZone,
   CalendarDate,
 } from "@internationalized/date";
+import Link from "next/link";
 import { DatePicker } from "@heroui/date-picker";
 const AccountEditPage = () => {
   // 统一表单对象
@@ -68,7 +68,11 @@ const AccountEditPage = () => {
     <div className="w-full h-full">
       <form className="overflow-hidden" onSubmit={handleSubmit}>
         <div className="bg-[#fff] pr-2.5 pl-2.5 w-full text-center text-base h-11 leading-11 font-semibold relative text-[#0b0b0b]">
-          <a href="/customer/account" className="absolute left-2.5 text-2xl inline-block top-1/2  -translate-y-1/2">
+           <Link
+              className="absolute left-2.5 text-2xl inline-block top-1/2  -translate-y-1/2"
+              href="/customer/account"
+              aria-label="Go to customer account page"
+            >
             <svg
               xmlns="http://www.w3.org/2000/svg"
               width="24"
@@ -84,7 +88,7 @@ const AccountEditPage = () => {
                 d="M15 18L9 12L15 6"
               ></path>
             </svg>
-          </a>
+          </Link>
           <span className="vipReturnTitles">Account Information</span>
         </div>
         <input name="form_key" type="hidden" value="kW7wucXHATeeem75"></input>

文件差異過大導致無法顯示
+ 214 - 0
src/app/(public)/customer/account/mypoints/page.tsx


+ 20 - 7
src/app/(public)/customer/account/page.tsx

@@ -3,6 +3,7 @@ import React from "react";
 import { useState } from "react";
 import SettingModal from "@/components/customer/SettingModal";
 import AccountSwiper from "@components/customer/accountSwiper";
+import Link from "next/link";
 const orderNavs = [
   {
     href: "/sales/order/history/#all",
@@ -45,7 +46,7 @@ const MyAccountPage = () => {
         </h1>
         <div
           className="absolute top-2.5 right-2.5 z-[99999]"
-          onClick={(e) => {
+          onClick={() => {
             setShowSetting(true);
           }}
         >
@@ -90,17 +91,29 @@ const MyAccountPage = () => {
 
         {/* 积分 / 优惠券 / 余额 */}
         <div className="flex justify-around items-center p-4 pt-0 pb-0  mt-5 text-sm ">
-          <a href="/customer/account/mypoints" className="leading-5">
+          <Link
+            className="leading-5"
+            href="/customer/account/mypoints"
+            aria-label="Go to customer account mypoints page"
+          >
             <strong>99999</strong> <br /> Points
-          </a>
+          </Link>
           <div>|</div>
-          <a href="/customer/account/mycoupon" className="leading-5">
+          <Link
+            className="leading-5"
+            href="/customer/account/mycoupon"
+            aria-label="Go to customer account mycoupon page"
+          >
             <strong className="coupons-number">0</strong> <br /> Coupon
-          </a>
+          </Link>
           <div>|</div>
-          <a href="/koc/user/mybalance" className="leading-5">
+            <Link
+            className="leading-5"
+            href="/koc/user/mybalance"
+            aria-label="Go to koc user mybalance page"
+          >
             <strong>$0</strong> <br /> Balance
-          </a>
+          </Link>
         </div>
 
         {/* VIP 等级 */}

+ 308 - 0
src/app/(public)/customer/account/pointlist/page.tsx

@@ -0,0 +1,308 @@
+"use client";
+// import Image from "next/image";
+import React, { useState, useEffect, useRef, useCallback } from "react";
+
+// 模拟积分明细数据(可替换为接口请求)
+const mockPointsData = [
+  {
+    id: 1,
+    type: "rewarded",
+    title: "Check In",
+    points: "+10 Points",
+    date: "May 17, 2026 11:07 PM",
+    currentPoints: "My points:100009",
+  },
+  {
+    id: 2,
+    type: "rewarded",
+    title: "Points Return of Redeem Hair Usage",
+    points: "+12000 Points",
+    date: "Oct 23, 2025 1:11 AM",
+    currentPoints: "My points:99999",
+  },
+  {
+    id: 3,
+    type: "used",
+    title: "Points Redeem Hair",
+    points: "-6000 Points",
+    date: "Oct 17, 2025 10:27 PM",
+    currentPoints: "My points:87999",
+  },
+  {
+    id: 4,
+    type: "used",
+    title: "Points Redeem Hair",
+    points: "-6000 Points",
+    date: "Oct 17, 2025 10:25 PM",
+    currentPoints: "My points:93999",
+  },
+  {
+    id: 5,
+    type: "rewarded",
+    title: "Updated by Admin",
+    points: "+99999 Points",
+    date: "Oct 17, 2025 10:24 PM",
+    currentPoints: "My points:99999",
+  },
+  {
+    id: 6,
+    type: "used",
+    title: "Points Redeem Giftcard",
+    points: "-300 Points",
+    date: "Oct 13, 2025 8:41 PM",
+    currentPoints: "My points:0",
+  },
+  {
+    id: 7,
+    type: "rewarded",
+    title: "Reward for Registering",
+    points: "+200 Points",
+    date: "Jun 9, 2025 7:39 PM",
+    currentPoints: "My points:300",
+  },
+  {
+    id: 8,
+    type: "rewarded",
+    title: "Reward for Signing up Newsletter",
+    points: "+100 Points",
+    date: "Jun 9, 2025 7:39 PM",
+    currentPoints: "My points:100",
+  },
+  // 补充测试数据(凑够分页演示)
+  {
+    id: 9,
+    type: "rewarded",
+    title: "Check In",
+    points: "+10 Points",
+    date: "May 16, 2026 10:00 PM",
+    currentPoints: "My points:100000",
+  },
+  {
+    id: 10,
+    type: "used",
+    title: "Points Redeem Accessory",
+    points: "-500 Points",
+    date: "May 15, 2026 9:00 AM",
+    currentPoints: "My points:99990",
+  },
+  {
+    id: 11,
+    type: "rewarded",
+    title: "Review Product",
+    points: "+50 Points",
+    date: "May 14, 2026 8:00 PM",
+    currentPoints: "My points:100490",
+  },
+  {
+    id: 12,
+    type: "rewarded",
+    title: "Refer a Friend",
+    points: "+200 Points",
+    date: "May 13, 2026 7:00 PM",
+    currentPoints: "My points:100440",
+  },
+  {
+    id: 13,
+    type: "used",
+    title: "Points Redeem Cash",
+    points: "-1000 Points",
+    date: "May 12, 2026 6:00 PM",
+    currentPoints: "My points:100240",
+  },
+  {
+    id: 14,
+    type: "rewarded",
+    title: "Check In",
+    points: "+10 Points",
+    date: "May 11, 2026 5:00 PM",
+    currentPoints: "My points:101240",
+  },
+];
+
+const PointsDetails = () => {
+  // 状态管理
+  const [activeTab, setActiveTab] = useState("all"); // 激活标签:all/rewarded/used
+  const [listData, setListData] = useState([]); // 展示的列表数据
+  const [page, setPage] = useState(1); // 当前页码
+  const [loading, setLoading] = useState(false); // 加载状态
+  const [hasMore, setHasMore] = useState(true); // 是否有更多数据
+  const listRef = useRef(null); // 列表容器ref,用于监听滚动
+
+  // 每页展示12条
+  const PAGE_SIZE = 12;
+  const fetchData = useCallback((page: number, tab: string) => {
+    return new Promise((resolve) => {
+        setTimeout(() => {
+          let data = mockPointsData;
+          const prePage = page - 1;
+          const start = prePage * PAGE_SIZE;
+          const end = page * PAGE_SIZE;
+          if (tab === "rewarded") {
+            data = mockPointsData.filter(
+              (item) => item.type === "rewarded",
+            );
+          } else if (tab === "used") {
+            data = mockPointsData.filter((item) => item.type === "used");
+          }
+          const res = data.slice(start, end);
+          resolve(res);
+        }, 800);
+    });
+  },[]);
+  // 加载更多数据
+  const loadMore = useCallback(() => {
+
+    setLoading(true);
+    
+    fetchData(page+1,activeTab).then((res) => {
+
+        setListData(res);
+
+        setLoading(false);
+        setPage(page+1);
+        if(res.length < PAGE_SIZE) {
+           setHasMore(false);
+        }
+    });
+  },[fetchData,page,activeTab]);
+  
+  // 初始化
+  useEffect(() => {
+    // 筛选数据
+    fetchData(1,'all').then((result)=> {
+        
+        setListData(result);
+        // 判断是否有更多数据
+        setHasMore(!(result.length < PAGE_SIZE));
+    });
+    
+  }, []);
+
+  // 监听滚动:触底加载
+  useEffect(() => {
+    const handleScroll = () => {
+      if (loading || !hasMore) return;
+      const container = listRef.current;
+      // 滚动到底部的判断:滚动高度 + 可视高度 ≥ 总高度 - 20(阈值)
+      if (
+        container.scrollTop + container.clientHeight >=
+        container.scrollHeight - 20
+      ) {
+        loadMore();
+      }
+    };
+
+    const container = listRef.current;
+    if (container) {
+      container.addEventListener("scroll", handleScroll);
+      return () => container.removeEventListener("scroll", handleScroll);
+    }
+  }, [loading, hasMore, loadMore]);
+
+  const clickActiveTab = (tab: string) => {
+      setActiveTab(tab);
+      setPage(1);
+      fetchData(1, tab);
+  }
+
+  return (
+    <div className="min-h-screen bg-white">
+      {/* 顶部导航栏 */}
+      <div className="sticky top-0 z-10 bg-white border-b border-gray-100 py-4 px-4 flex items-center">
+        {/* 返回按钮 */}
+        <button className="mr-4">
+          <svg viewBox="0 0 24 24" width="20" height="20" fill="black">
+            <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
+          </svg>
+        </button>
+        {/* 标题 */}
+        <h1 className="text-xl font-bold text-black">Points Details</h1>
+      </div>
+
+      {/* 标签切换栏 */}
+      <div className="flex border-b border-gray-200">
+        <button
+          onClick={() => clickActiveTab("all")}
+          className={`px-6 py-3 font-medium text-sm ${
+            activeTab === "all"
+              ? "bg-black text-white"
+              : "bg-white text-gray-600 hover:bg-gray-50"
+          }`}
+        >
+          ALL
+        </button>
+        <button
+          onClick={() => clickActiveTab("rewarded")}
+          className={`px-6 py-3 font-medium text-sm ${
+            activeTab === "rewarded"
+              ? "bg-black text-white"
+              : "bg-white text-gray-600 hover:bg-gray-50"
+          }`}
+        >
+          REWARDED
+        </button>
+        <button
+          onClick={() => clickActiveTab("used")}
+          className={`px-6 py-3 font-medium text-sm ${
+            activeTab === "used"
+              ? "bg-black text-white"
+              : "bg-white text-gray-600 hover:bg-gray-50"
+          }`}
+        >
+          USED
+        </button>
+      </div>
+
+      {/* 积分明细列表(带滚动监听) */}
+      <div ref={listRef} className="h-[calc(100vh-120px)] overflow-y-auto">
+        {listData.length > 0 ? (
+          <div className="divide-y divide-gray-100">
+            {listData.map((item) => (
+              <div key={item.id} className="px-4 py-4">
+                {/* 左侧:标题+日期 */}
+                <div className="flex justify-between items-start">
+                  <div>
+                    <h3 className="text-base font-medium text-black">
+                      {item.title}
+                    </h3>
+                    <p className="text-xs text-gray-500 mt-1">{item.date}</p>
+                  </div>
+                  {/* 右侧:积分变动 */}
+                  <div className="text-right">
+                    <p
+                      className={`text-base font-medium ${
+                        item.points.startsWith("+")
+                          ? "text-black"
+                          : "text-black"
+                      }`}
+                    >
+                      {item.points}
+                    </p>
+                    <p className="text-xs text-gray-500 mt-1">
+                      {item.currentPoints}
+                    </p>
+                  </div>
+                </div>
+              </div>
+            ))}
+          </div>
+        ) : (
+          // 空数据提示
+          <div className="flex items-center justify-center h-32">
+            <p className="text-gray-500 text-sm">NO DATA</p>
+          </div>
+        )}
+
+        {/* 加载中/无更多提示 */}
+        <div className="px-4 py-3 text-center text-sm">
+          {loading && <p className="text-gray-500">Loading...</p>}
+          {!loading && !hasMore && (
+            <p className="text-gray-500">NO MORE DATA</p>
+          )}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default PointsDetails;

+ 5 - 5
src/app/(public)/customer/address/new/page.tsx

@@ -1,7 +1,7 @@
 "use client";
 import React from "react";
 import { useState } from "react";
-import { useEffect } from "react";
+// import { useEffect } from "react";
 const NewAddressPage = () => {
   // 统一表单对象
   const [form, setForm] = useState({
@@ -25,10 +25,10 @@ const NewAddressPage = () => {
   // 统一提交
   const handleSubmit = (e) => {
     e.preventDefault();
-    const submitData = {
-      ...form,
-      street: [form.street], // 👈 自动变成数组,后端就能收到 street[]
-    };
+    // const submitData = {
+    //   ...form,
+    //   street: [form.street], // 👈 自动变成数组,后端就能收到 street[]
+    // };
 
     // 直接拿form所有数据
     console.log("表单数据:", form);

+ 2 - 2
src/app/(public)/customer/address/page.tsx

@@ -1,7 +1,7 @@
 "use client";
 import React from "react";
-import { useState } from "react";
-import { useEffect } from "react";
+// import { useState } from "react";
+// import { useEffect } from "react";
 const CustomerAddressPage = () => {
   // 模拟地址数据(可根据实际需求替换)
   const addressData = {

+ 3 - 5
src/app/(public)/product/[...urlProduct]/page.tsx

@@ -16,8 +16,6 @@ import {
   ProductOption,
   SingleProductResponse,
   ProductMediaType,
-  ProductFlexibleVariant,
-  ResolvedVariant
 } from "@components/catalog/type";
 import { RelatedProductsSection } from "@components/catalog/product/RelatedProductsSection";
 import { HeroCarouselShimmer } from "@components/common/slider";
@@ -87,9 +85,9 @@ export default async function ProductPage({
 
   const flexibleVariants = formatFlexibleVariants(product?.flexibleVariants);
 
-    const reviews = Array.isArray(product?.reviews?.edges)
-    ? product?.reviews.edges.map((e) => e.node)
-    : [];
+    // const reviews = Array.isArray(product?.reviews?.edges)
+    // ? product?.reviews.edges.map((e) => e.node)
+    // : [];
 
   // const VariantImages = isArray(product?.variants?.edges)
   //   ? product?.variants.edges.map(

+ 8 - 9
src/app/(public)/product/_components/ProductInformation.tsx

@@ -16,7 +16,6 @@ import {
     getFirstAvailable,
     getAvailableVariants,
     isCombinationAvailable,
-    formatFlexibleVariants,
     findNearestAvailableVariant
 } from "@/utils/variantTools";
 import { Price } from "@components/theme/ui/Price";
@@ -95,7 +94,7 @@ export function ProductInformation({
     const handleOptionClick = (optionId: number, valueId: number) => {
         // 更新前需要判断当前选中的组合是否可以购买,如果可以购买正常更新;如果不能购买查找可以购买的组合然后更新
         let newSelected: Record<number, number> = {...selected,[optionId]: valueId};
-        let selectedValueIds = Object.values(newSelected);
+        const selectedValueIds = Object.values(newSelected);
         if(!isCombinationAvailable(selectedValueIds, availableVariants)) {
             newSelected = findNearestAvailableVariant(optionId,valueId,{...newSelected},productOptions,availableVariants);
         }
@@ -127,7 +126,7 @@ export function ProductInformation({
         let totalLinePrice = 0;
         let totalNowPrice = 0;
         let save = 0;
-        let variant = flexibleVariants.find((v) => {
+        const variant = flexibleVariants.find((v) => {
             const vIds = v.optionValues.map((ov) => ov.id);
             return selectedIds.length === vIds.length && selectedIds.every((id) => vIds.includes(id));
         });
@@ -153,10 +152,10 @@ export function ProductInformation({
     }, [selected, flexibleVariants, productQty]);
 
 
-    let classNameOptionValueBtn = "text-ly-14 leading-ly-24 border border-solid rounded-lg pt-1.5 pb-1.5 pl-3 pr-3 bg-white";
+    const classNameOptionValueBtn = "text-ly-14 leading-ly-24 border border-solid rounded-lg pt-1.5 pb-1.5 pl-3 pr-3 bg-white";
 
 
-    let handlerProductQty = (action: string) => {
+    const handlerProductQty = (action: string) => {
         if (action === "increase") {
             setProductQty(productQty + 1);
         } else if (action === "decrease" && productQty > 1) {
@@ -166,12 +165,12 @@ export function ProductInformation({
 
     async function addProductToCart(action:string = 'addtocart') {
         
-        let params = { 
+        const params = { 
             productId: String(productId), 
             quantity: productQty,
             variantId: currentVariantInfo.variant?._id,
         };
-        let res = await onAddToCart(params);
+        const res = await onAddToCart(params);
         console.log('onAddToCart result --- ', res);
         if(action === 'buynow') {
             if(res) {
@@ -183,7 +182,7 @@ export function ProductInformation({
         }
     } 
 
-    let addToCartHandler = async () => {
+    const addToCartHandler = async () => {
    
         if(!isCurrentSelectionAvailable) {
             showToast("The selected options are not available!", "warning");
@@ -195,7 +194,7 @@ export function ProductInformation({
         }
     };
 
-    let buyNowHandler = () => {
+    const buyNowHandler = () => {
         if(!isCurrentSelectionAvailable) {
             showToast("The selected options are not available!", "warning");
             return;

+ 1 - 1
src/app/(public)/product/_components/ProductMedia.tsx

@@ -34,7 +34,7 @@ export function ProductMedia({ mediaData }: {mediaData: Array<ProductMediaType>;
                 {
                     mediaData.map((img) => {
                         return (
-                            <SwiperSlide>
+                            <SwiperSlide key={img.id}>
                                 <Image className="block w-full"
                                     src={getImageUrl(img.publicPath,baseUrl)}
                                     width={390}

+ 1 - 1
src/app/(public)/product/_components/review/ReviewDetail.tsx

@@ -47,7 +47,7 @@ const ReviewDetail: FC<ReviewDetailProps> = ({
               reviewCount={totalReview}
             />
           </div>
-
+          <span style={{display:"none"}}>{productId}</span>
           <div className="flex w-full max-w-[280px] overflow-hidden rounded-sm">
             {Object.entries(ratingCounts)
               .reverse()

+ 5 - 5
src/app/api/graphql/route.ts

@@ -17,7 +17,7 @@ import {
     CREATE_CHECKOUT_PAYMENT_METHODS,
     CREATE_CHECKOUT_ORDER,
     CREATE_PRODUCT_REVIEW,
-    GET_PRODUCT_BY_URL_KEY,
+    // GET_PRODUCT_BY_URL_KEY,
 } from "@/graphql";
 
 const ALLOWED_OPERATIONS: Record<string, any> = {
@@ -36,9 +36,9 @@ const ALLOWED_OPERATIONS: Record<string, any> = {
     CreateCheckoutOrder: CREATE_CHECKOUT_ORDER,
     CreateProductReview: CREATE_PRODUCT_REVIEW,
 };
-const QUERY_OPERATIONS: Record<string, any> = {
-    GetProductById: GET_PRODUCT_BY_URL_KEY,
-}
+// const QUERY_OPERATIONS: Record<string, any> = {
+//     GetProductById: GET_PRODUCT_BY_URL_KEY,
+// }
 
 interface FetchOption  {
     query: string;
@@ -50,7 +50,7 @@ interface FetchOption  {
 
 // 需要authorization的operation
 function authorizationOperations(body: Record<string, any>,req:NextRequest): FetchOption {
-    const { operationName, query: bodyGraphqlQuery, variables } = body;
+    const { operationName, variables } = body;
     const guestToken = getAuthToken(req);
     const query = ALLOWED_OPERATIONS[operationName];
     let finalVariables = variables;

+ 7 - 7
src/components/Portal.tsx

@@ -1,16 +1,16 @@
 'use client';
 
-import { useEffect, useState } from 'react';
+// import { useEffect, useState } from 'react';
 import { createPortal } from 'react-dom';
 
 export default function Portal({ children }: { children: React.ReactNode }) {
-  const [mounted, setMounted] = useState(false);
+  // const [mounted, setMounted] = useState(false);
 
-  // useEffect 只会在客户端执行,服务端渲染时不会运行(Next.js 在服务器端会跳过所有 useEffect / useLayoutEffect)。
-  useEffect(() => {
-    setMounted(true); // 组件挂载后,把标志位置为 true
-  }, []); // 空依赖数组,仅执行一次
+  // // useEffect 只会在客户端执行,服务端渲染时不会运行(Next.js 在服务器端会跳过所有 useEffect / useLayoutEffect)。
+  // useEffect(() => {
+  //   setMounted(true); // 组件挂载后,把标志位置为 true
+  // }, []); // 空依赖数组,仅执行一次
 
-  if (!mounted) return null; // SSR 时不渲染,避免 hydration 错误
+  // if (!mounted) return null; // SSR 时不渲染,避免 hydration 错误
   return createPortal(children, document.body);
 }

+ 5 - 13
src/components/cart/CartModal.tsx

@@ -2,13 +2,6 @@
 import clsx from "clsx";
 import { useDisclosure } from "@heroui/use-disclosure";
 import { AnimatePresence, motion } from "framer-motion";
-import {
-  Drawer,
-  DrawerBody,
-  DrawerContent,
-  DrawerFooter,
-  DrawerHeader,
-} from "@heroui/drawer";
 import { ShoppingCartIcon } from "@heroicons/react/24/outline";
 import { DEFAULT_OPTION } from "@/utils/constants";
 import { useAppSelector } from "@/store/hooks";
@@ -27,7 +20,6 @@ import { redirectToCheckout } from "@/utils/actions";
 import { EMAIL, getLocalStorage } from "@/store/local-storage";
 import Link from "next/link";
 import { createUrl, isCheckout, safeParse } from "@utils/helper";
-import { useMediaQuery } from "@utils/hooks/useMediaQueryHook";
 import { useBodyScrollLock } from "@utils/hooks/useBodyScrollLock";
 import { useSyncExternalStore } from "react";
 import { useAddressesFromApi } from "@utils/hooks/getAddress";
@@ -75,11 +67,11 @@ export default function CartModal({
 
   useBodyScrollLock(finalIsOpen);
 
-  const handleOpenChange = (open: boolean) => {
-    if (!open) {
-      finalOnClose?.();
-    }
-  };
+  // const handleOpenChange = (open: boolean) => {
+  //   if (!open) {
+  //     finalOnClose?.();
+  //   }
+  // };
 
   return (
     <>

+ 9 - 8
src/components/common/AddToCartModal/AddToCartModal.tsx

@@ -35,7 +35,7 @@ import {
     findNearestAvailableVariant
 } from "@/utils/variantTools";
 
-export function AddToCartModal() {
+export default function AddToCartModal() {
     const dispatch = useAppDispatch();
     const {isOpen, product} = useAppSelector((state) => state.addToCartDialog);
 
@@ -52,7 +52,8 @@ export function AddToCartModal() {
     },[product?.flexibleVariants]);
 
     const productOptions: ProductOption[] = useMemo(() => {
-        return product?.productOptions ? JSON.parse(product.productOptions) : [];
+        const opts = product?.productOptions;
+        return opts ? JSON.parse(opts) : [];
     },[product?.productOptions]);
 
     // 获取所有可用变体
@@ -62,7 +63,7 @@ export function AddToCartModal() {
 
     const isSaleable = product?.isSaleable;
 
-    const [productQty, setProductQty] = useState(1);
+    const [productQty] = useState(1);
 
 
     // 记录当前哪个选项组刚刚被点击(用于实现“点击组内全部可点”)
@@ -136,7 +137,7 @@ export function AddToCartModal() {
         let totalLinePrice = 0;
         let totalNowPrice = 0;
         let save = 0;
-        let variant = flexibleVariants.find((v) => {
+        const variant = flexibleVariants.find((v) => {
             const vIds = v.optionValues.map((ov) => ov.id);
             return selectedIds.length === vIds.length && selectedIds.every((id) => vIds.includes(id));
         });
@@ -167,9 +168,9 @@ export function AddToCartModal() {
         clickValueId: number;
     }) => {
         // 更新前需要判断当前选中的组合是否可以购买,如果可以购买正常更新;如果不能购买查找可以购买的组合然后更新
-        let {clickOptionId: optionId, clickValueId: valueId} = result;
+        const {clickOptionId: optionId, clickValueId: valueId} = result;
         let newSelected: Record<number, number> = {...selected,[optionId]: valueId};
-        let selectedValueIds = Object.values(newSelected);
+        const selectedValueIds = Object.values(newSelected);
         if(!isCombinationAvailable(selectedValueIds, availableVariants)) {
             newSelected = findNearestAvailableVariant(optionId,valueId,{...newSelected},productOptions,availableVariants);
         }
@@ -181,12 +182,12 @@ export function AddToCartModal() {
 
     async function addProductToCart(action:string = 'addtocart') {
             
-        let params = { 
+        const params = { 
             productId: String(product?._id), 
             quantity: productQty,
             variantId: currentVariantInfo.variant?._id,
         };
-        let res = await onAddToCart(params);
+        const res = await onAddToCart(params);
         console.log('onAddToCart run ----- 1');
         if(action === 'buynow') {
             if(res) {

+ 3 - 1
src/components/common/AddToCartModal/AddToCartModalWrapper.tsx

@@ -1,8 +1,10 @@
 "use client";
 
-import { AddToCartModal } from "@components/common/AddToCartModal/AddToCartModal";
+// import { AddToCartModal } from "@components/common/AddToCartModal/AddToCartModal";
 import { useAppSelector } from "@/store/hooks";
+import dynamic from 'next/dynamic';
 
+const AddToCartModal = dynamic(() => import("./AddToCartModal"),{ssr: false});
 export function AddToCartModalWrapper() {
   const {product} = useAppSelector((state) => state.addToCartDialog);
 

+ 2 - 2
src/components/common/AddToCartModal/OpenAddToCartModalButton.tsx

@@ -20,13 +20,13 @@ export function OpenAddToCartModalButton({productUrlKey}: {productUrlKey: string
     const openDialog = async () => {
         if( loading) return; 
         try {
-            let result = await getContent({
+            const result = await getContent({
                 variables: { urlKey: productUrlKey }
             });
 
             console.log('product ----- ', result);// 返回的数据中有__typename,如何过滤 @todo
 
-            let productData = result?.data?.product;
+            const productData = result?.data?.product;
             if(result.error) {
                 showToast(result.error.message, "danger");
             } else {

+ 1 - 1
src/components/common/AddToCartModal/ProductOptionsInAddToCartModal.tsx

@@ -20,7 +20,7 @@ export default function ProductOptionsInAddToCartModal({
     }) => void;
 }) {
 
-    let classNameOptionValueBtn = "text-ly-14 leading-ly-24 border border-solid rounded-lg pt-1.5 pb-1.5 pl-3 pr-3 bg-white";
+    const classNameOptionValueBtn = "text-ly-14 leading-ly-24 border border-solid rounded-lg pt-1.5 pb-1.5 pl-3 pr-3 bg-white";
     // 处理选项点击
     const handleOptionClick = (optionId: number, valueId: number) => {
         onOptionClick({

+ 177 - 0
src/components/customer/PointsRule.tsx

@@ -0,0 +1,177 @@
+"use client";
+import Image from "next/image";
+export default function PointsRuleModal({
+  visible,
+  handleCloseModal,
+}: {
+  visible: boolean;
+  handleCloseModal: () => void;
+}) {
+  // 如果不显示,直接 return null
+  if (!visible) return null;
+
+  return (
+    <div
+      id="modal-overlay"
+      onClick={handleCloseModal}
+      className="fixed inset-0 bg-black/70 z-50 flex items-start justify-center overflow-y-auto"
+    >
+      {/* 弹窗内容区 */}
+      <div className="bg-white w-full max-w-2xl max-h-[100vh] overflow-y-auto  p-6 pt-16 ">
+        {/* 返回按钮 */}
+        <button
+          id="back-btn"
+          onClick={handleCloseModal}
+          className="fixed w-full bg-[#000] h-15.5 leading-15.5 justify-center text-xl  left-0 top-0  z-50 mb-4 flex items-center gap-1 text-white  transition-colors"
+        >
+            <Image src="/image/account/202605201502.png" width={22} style={{left:"8.2051vw",position:"absolute"}} height={22} alt="back" />
+         POINTS RULES
+        </button>
+
+        <div className="space-y-6">
+          {/* What Are Reward Points? */}
+          <section className="space-y-2">
+            <h3 className="text-lg font-bold text-black">
+              What Are Reward Points?
+            </h3>
+            <p className="text-sm text-gray-700 leading-relaxed">
+              We love to say thank you to our loyal customers for shopping with
+              us. Reward Points are an added bonus and just one of the ways we
+              like to say thanks. You can earn Points for every purchase you
+              make online, as well as bonus Points for other actions such as
+              referring a friend. Any Points you earn can be used towards your
+              future purchases online.
+            </p>
+          </section>
+
+          {/* How do I get Bonus Point? */}
+          <section className="space-y-3">
+            <h3 className="text-lg font-bold text-black">
+              How do I get Bonus Point?
+            </h3>
+            <p className="text-sm text-gray-700">
+              You can get bonus point from the following methods.
+            </p>
+            <ol className="list-decimal pl-5 space-y-2 text-sm text-gray-700">
+              <li>
+                <span className="font-bold">Buy and Save</span>
+                <p className="pl-2">
+                  You'll earn 1 point for every dollar spent on your purchase.
+                </p>
+              </li>
+              <li>
+                <span className="font-bold">Registration</span>
+                <p className="pl-2">
+                  You can get 200 bonus points for register to be Alipearl Hair
+                  Hair New Member.
+                </p>
+              </li>
+              <li>
+                <span className="font-bold">Sign In</span>
+                <p className="pl-2">
+                  You can get 10 bonus points when you sign in every time and
+                  the total amount you can get in one day is 10 bonus points
+                  only.
+                </p>
+              </li>
+              <li>
+                <span className="font-bold">Reviewing Our Products</span>
+                <p className="pl-2">
+                  You can earn points from writing reviews on our products.
+                  Submitting your review earn 50 points. Under this
+                  circumstance, all you can get in one day is 50 bonus points
+                  only.
+                </p>
+              </li>
+              <li>
+                <span className="font-bold">Referring A friend</span>
+                <p className="pl-2">
+                  Want to share the love with your friends and family? Invite
+                  them to shop with us and as a thank you we'll award you 200
+                  Reward Points when they place their first order. Head to the
+                  My Invitations section of your account.
+                </p>
+              </li>
+            </ol>
+          </section>
+
+          {/* Do I have to be registered to earn Points? */}
+          <section className="space-y-2">
+            <h3 className="text-lg font-bold text-black">
+              Do I have to be registered to earn Points?
+            </h3>
+            <p className="text-sm text-gray-700 leading-relaxed">
+              Yes you need to be registered to earn and spend Reward Points.
+              Registering an account is easy, and can be done prior to placing
+              your first order, or as part of the checkout process. Once you're
+              registered, simply sign in to your account before placing any
+              orders. Each time you make a purchase you'll then automatically
+              earn Points, which will be available for you to use at checkout on
+              future orders.
+            </p>
+          </section>
+
+          {/* Do my Reward Points expire? */}
+          <section className="space-y-2">
+            <h3 className="text-lg font-bold text-black">
+              Do my Reward Points expire?
+            </h3>
+            <p className="text-sm text-gray-700">
+              Yes, any unused Reward Points expire after 6 months (180 days).
+            </p>
+          </section>
+
+          {/* Is there a maximum amount of Reward Points I can redeem per order? */}
+          <section className="space-y-2">
+            <h3 className="text-lg font-bold text-black">
+              Is there a maximum amount of Reward Points I can redeem per order?
+            </h3>
+            <p className="text-sm text-gray-700">
+              Yes, the maximum reward points amount that you can redeem per
+              order is 20000 points.
+            </p>
+          </section>
+
+          {/* What are my Reward Points Worth? */}
+          <section className="space-y-2">
+            <h3 className="text-lg font-bold text-black">
+              What are my Reward Points Worth?
+            </h3>
+            <p className="text-sm text-gray-700">
+              100 Rewards Points = $1.25 which can be used towards any future
+              purchases.
+            </p>
+          </section>
+
+          {/* Terms of Use */}
+          <section className="space-y-2">
+            <h3 className="text-lg font-bold text-black">Terms of Use</h3>
+            <p className="text-sm text-gray-700 leading-relaxed">
+              Your participation in the Rewards Points programme and the
+              administration of your Rewards Points balance is entirely at our
+              discretion. We reserve the right to cancel your account or adjust
+              your Reward Points balance without notice or explanation.
+              <br />
+              If you earn or spend Points for an order which is subsequently
+              cancelled or amended for any reason, we reserve the right to
+              reverse some or all of the Points earned at our discretion.
+              <br />
+              If you earn Points for referring additional customers, we reserve
+              the right to review these new customer accounts, and reverse some
+              or all of the Points earned at our discretion.
+              <br />
+              Reward Points are not legal tender and are in no way redeemable
+              for cash or any other benefit.
+              <br />
+              Reward Points balances are not transferable under any
+              circumstances.
+              <br />
+              Your use of the Reward Points programme indicates your acceptance
+              of these terms of us.
+            </p>
+          </section>
+        </div>
+      </div>
+    </div>
+  );
+}

+ 2 - 5
src/components/home/CategoryCarousel.tsx

@@ -71,7 +71,7 @@ interface CategoryCarouselProps {
 const CategoryCarousel: FC<CategoryCarouselProps> = async ({
   options: _options,
 }) => {
-  try {
+  
     const {data} = await cachedGraphQLRequest<CategoriesResponse>(
       "home",
       GET_HOME_CATEGORIES,
@@ -155,10 +155,7 @@ const CategoryCarousel: FC<CategoryCarouselProps> = async ({
         </div>
       </section>
     );
-  } catch (error) {
-    console.error("Error fetching categories:", error);
-    return null;
-  }
+
 };
 
 export default CategoryCarousel;

+ 2 - 9
src/components/home/ProductCarousel.tsx

@@ -19,7 +19,7 @@ const ProductCarousel: FC<ProductCarouselProps> = async ({
   sortOrder,
 }) => {
   const { filters, title } = options;
-  try {
+
     const { sort, limit, ...rest } = filters || {};
     const filterObject: Record<string, string> = {};
     Object.entries(rest).forEach(([key, value]) => {
@@ -78,14 +78,7 @@ const ProductCarousel: FC<ProductCarouselProps> = async ({
         products={products}
       />
     );
-  } catch (error) {
-    console.error("Error fetching products for carousel:", {
-      title,
-      filters,
-      error: error instanceof Error ? error.message : error,
-    });
-    return null;
-  }
+
 };
 
 export default ProductCarousel;

+ 0 - 1
src/components/layout/navbar/MobileMenu.tsx

@@ -4,7 +4,6 @@ import { AnimatePresence, motion } from "framer-motion";
 import Link from "next/link";
 
 import { MobileSearchBar } from "./MobileSearch";
-import { useState } from "react";
 import { useBodyScrollLock } from "@utils/hooks/useBodyScrollLock";
 
 interface MobileMenuProps {

+ 11 - 66
src/components/theme/filters/SortOrder.tsx

@@ -4,7 +4,7 @@ import { SORT, SortOrderTypes } from "@/utils/constants";
 import { createUrl } from "@/utils/helper";
 import { Select, SelectItem } from "@heroui/select";
 import { usePathname, useRouter, useSearchParams } from "next/navigation";
-import { FC, useState, useEffect } from "react";
+import { FC } from "react";
 import {
   Drawer,
   DrawerContent,
@@ -20,18 +20,14 @@ import { SortIcon } from "@components/common/icons/SortIcon";
 const SortOrder: FC<{
   sortOrders: SortOrderTypes[];
   title: string;
-}> = ({ sortOrders, title }) => {
+}> = ({ sortOrders }) => {
   const searchParams = useSearchParams();
   const pathname = usePathname();
   const router = useRouter();
   const sort = searchParams.get(SORT) || "name-asc";
 
   const { isOpen, onOpen, onOpenChange } = useDisclosure();
-  const [tempSort, setTempSort] = useState(sort);
 
-  useEffect(() => {
-    setTempSort(sort);
-  }, [sort]);
 
   const handleSortChange = (value: string) => {
     const newParams = new URLSearchParams(searchParams.toString());
@@ -42,10 +38,7 @@ const SortOrder: FC<{
     router.replace(newUrl);
   };
 
-  const applySort = () => {
-    handleSortChange(tempSort);
-    onOpenChange();
-  };
+
 
   const clearFilters = () => {
     const q = searchParams.get("q");
@@ -57,50 +50,9 @@ const SortOrder: FC<{
 
   return (
     <>
-      {/* Desktop View */}
-      <section className="hidden md:flex w-64 items-center gap-x-2.5">
-        <p
-          id="sort-label"
-          className="leading-0 text-nowrap min-[1300]:block hidden"
-        >
-          {title}
-        </p>
-        <Select
-          defaultOpen={false}
-          aria-label={title}
-          aria-labelledby="sort-label"
-          selectedKeys={[sort]}
-          isMultiline={false}
-          items={sortOrders}
-          placeholder="Select a Sort Order"
-          classNames={{
-            value: "text-neutral-800 dark:text-neutral-200",
-          }}
-          renderValue={(items) => (
-            <div className="flex items-center gap-1.5 overflow-x-auto pb-1.5 pt-1">
-              {items.map((item) => (
-                <p key={item.key} className="text-neutral-800 dark:text-neutral-200">{item.data?.title}</p>
-              ))}
-            </div>
-          )}
-          size="md"
-          variant="flat"
-          onSelectionChange={(e) => handleSortChange(e.currentKey as string)}
-        >
-          {(order) => (
-            <SelectItem
-              key={order.value}
-              textValue={order.value}
-              className="text-neutral-800 dark:text-neutral-200"
-            >
-              {order.title}
-            </SelectItem>
-          )}
-        </Select>
-      </section>
-
+     
       {/* Mobile View Toggle */}
-      <div className="md:hidden flex flex-wrap gap-3">
+      <div className="flex flex-wrap gap-3">
         <Button
           size="md"
           variant="flat"
@@ -135,15 +87,7 @@ const SortOrder: FC<{
                         Clear all filters
                       </button>
                     )}
-                    <Button
-                      color="primary"
-                      radius="full"
-                      size="md"
-                      className="px-6 font-semibold"
-                      onPress={applySort}
-                    >
-                      Apply Filter
-                    </Button>
+                    
                   </div>
                 </div>
               </DrawerHeader>
@@ -154,7 +98,7 @@ const SortOrder: FC<{
                   </p>
                   <Select
                     aria-label="Sort options"
-                    selectedKeys={[tempSort]}
+                    selectedKeys={[sort]}
                     className="w-full"
                     variant="flat"
                     size="lg"
@@ -162,9 +106,10 @@ const SortOrder: FC<{
                       value: "text-neutral-800 dark:text-neutral-200",
                       trigger: "dark:bg-neutral-800",
                     }}
-                    onSelectionChange={(e) =>
-                      setTempSort(e.currentKey as string)
-                    }
+                    onSelectionChange={(e) => {
+                      handleSortChange(e.currentKey as string);
+                      onOpenChange();
+                    }}
                   >
                     {sortOrders.map((order) => (
                       <SelectItem

+ 1 - 1
src/lib/ApolloClientBrowser.ts

@@ -45,7 +45,7 @@ export default function makeClient() {
   });
 
 
-  const authLink = new SetContextLink(async (prevContext, operation) => {
+  const authLink = new SetContextLink(async (prevContext) => {
       
       const session = await getCachedSession();
       const userToken = session?.user?.accessToken;

+ 1 - 1
src/lib/ApolloClientServer.ts

@@ -23,7 +23,7 @@ export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
       },
       */
     });
-    const authLink = new SetContextLink((prevContext, operation) => {
+    const authLink = new SetContextLink((prevContext) => {
         const storefrontKey =
             process.env.BAGISTO_STOREFRONT_KEY ||
             process.env.NEXT_PUBLIC_BAGISTO_STOREFRONT_KEY ||

+ 3 - 46
src/lib/graphql-fetch.ts

@@ -1,5 +1,5 @@
-import { unstable_cache } from "next/cache";
-import { print, type DocumentNode } from "graphql";
+
+import { type DocumentNode } from "graphql";
 import {
   type OperationVariables,
   ApolloClient
@@ -7,50 +7,7 @@ import {
 
 import {getClient} from "@/lib/ApolloClientServer";
 
-import {
-  CombinedGraphQLErrors,
-  CombinedProtocolErrors,
-  LocalStateError,
-  ServerError,
-  ServerParseError,
-  UnconventionalError,
-} from "@apollo/client/errors";
 // Comprehensive error handling example. https://www.apollographql.com/docs/react/data/error-handling
-function handleError(error: unknown) {
-  let res = '';
-  if (CombinedGraphQLErrors.is(error)) {
-    // Handle GraphQL errors 发起请求前graphql的致命错误 直接抛出
-    throw error;
-  } /*else if (CombinedProtocolErrors.is(error)) {
-    // Handle multipart subscription protocol errors
-    error.errors.forEach((protocolError) => {
-      console.log(protocolError.message);
-      console.log(protocolError.extensions);
-    });
-  } */else if (LocalStateError.is(error)) { // 使用@client 报错时
-    // Handle errors thrown by the `LocalState` class
-    throw error;
-
-  } else if (ServerError.is(error)) {
-    // Handle server HTTP errors
-    res = `Response body: ${error.statusCode} / ${error.message}`;
-    // Handle unauthorized access
-    //  if (error.statusCode === 401) {
-    //    
-    //  }
-  } else if (ServerParseError.is(error)) {
-    // Handle JSON parse 
-     throw error;
-  } else if (UnconventionalError.is(error)) {
-    // Handle errors thrown by irregular types
-    throw error;
-
-  } else {
-    // Handle other errors
-    throw error;
-  }
-  return res;
-}
 
 export interface GraphqlRequestResult<TData = unknown> {
   data: TData | null;
@@ -137,7 +94,7 @@ export async function graphqlRequest<
   options?: GraphQLRequestOptions
 ): Promise<GraphqlRequestResult<TData>> {
   const client = getClient();
-  let resData, resError;
+  let resData;
   const revalidate = getRevalidateTime(options?.life);
   let queryOption: ApolloClient.QueryOptions<TData> = {
     query,

+ 1 - 1
src/lib/restApiClient.ts

@@ -42,7 +42,7 @@ export async function clientFetch(apiUrl: string, options: RequestInit) {
     const response = await fetch(apiUrl, options);
     // console.log('response -- ', response);
     if(response.ok) {
-        let result = await response.json();
+        const result = await response.json();
         return result;
     } else {
         return {

+ 1 - 1
src/providers/ApolloWrapper.tsx

@@ -1,7 +1,7 @@
 "use client";
 
 import { ApolloNextAppProvider } from "@apollo/client-integration-nextjs";
-import { ReactNode, useMemo } from "react";
+import { ReactNode } from "react";
 import makeClient from "@/lib/ApolloClientBrowser";
 
 const ApolloWrapper = ({ children }: { children: ReactNode }) => {

+ 1 - 1
src/store/slices/addToCartDialogSlice.ts

@@ -1,5 +1,5 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { SingleProductResponse, ProductNode } from "@/components/catalog/type";
+import { ProductNode } from "@/components/catalog/type";
 
 interface DialogState {
   isOpen: boolean;

+ 1 - 1
src/utils/bagisto/index.ts

@@ -105,7 +105,7 @@ export async function restApiFetch<T>({
       }
     }
 console.log('restApiFetch --- baseHeaders:', baseHeaders)
-    let param: RequestInit = {
+    const param: RequestInit = {
       method: method,
       headers: baseHeaders,
       cache,

+ 4 - 4
src/utils/hooks/useAddToCart.ts

@@ -37,7 +37,7 @@ export const useAddProduct = () => {
         }
         if (responseData) {
           if (responseData.success) {
-            let cartDetail = {
+            const cartDetail = {
               id: responseData.id,
               itemsQty: responseData.itemsQty,
               taxAmount: responseData.taxAmount,
@@ -83,7 +83,7 @@ export const useAddProduct = () => {
         return;
       }
     }
-    let param : { productId: number; quantity:number; variantId?: number; } = {
+    const param : { productId: number; quantity:number; variantId?: number; } = {
       productId: parseInt(productId),
       quantity,
     };
@@ -91,7 +91,7 @@ export const useAddProduct = () => {
       param.variantId = variantId;
     }
 
-    let result = await mutateAsync({
+    const result = await mutateAsync({
       variables: param,
     });
 
@@ -146,7 +146,7 @@ export const useAddProduct = () => {
         const responseData = response?.createUpdateCartItem?.updateCartItem;
 
         if (isObject(responseData)) {
-          let cartDetail = {
+          const cartDetail = {
             id: responseData.id,
             itemsQty: responseData.itemsQty,
             taxAmount: responseData.taxAmount,

+ 1 - 1
src/utils/hooks/useCartDetail.ts

@@ -21,7 +21,7 @@ export function useCartDetail() {
       onCompleted: (response) => {
         const cartData = response?.createReadCart?.readCart;
         if (cartData) {
-          let cartDetail = {
+          const cartDetail = {
             id: cartData.id,
             itemsQty: cartData.itemsQty,
             taxAmount: cartData.taxAmount,

+ 41 - 25
src/utils/hooks/useGuestCartToken.ts

@@ -1,6 +1,6 @@
 "use client";
 
-import { useEffect, useState, useRef } from "react";
+import { useState, useRef } from "react";
 import { fetchHandler } from "../fetch-handler";
 import { GUEST_CART_ID, GUEST_CART_TOKEN, IS_GUEST } from "@/utils/constants";
 import { encodeJWT, decodeJWT } from "@/utils/jwt-cookie";
@@ -11,9 +11,45 @@ import { CREATE_CART_TOKEN } from "@/graphql";
 // Main Hook
 // ---------------------------
 export const useGuestCartToken = () => {
-  const [token, setToken] = useState<string | null>(null);
-  const [cartId, setCartId] = useState<number | null>(null);
-  const [isReady, setIsReady] = useState(false);
+
+  const [token, setToken] = useState(() => {
+      const cookieToken = getCookie(GUEST_CART_TOKEN);
+      let guestCartToken: string | null = null;
+      console.log("cookieToken -----1 ", cookieToken);
+      if (cookieToken) {
+        console.log("cookieToken -----2 ", cookieToken);
+        const isGuest = getCookie(IS_GUEST) !== "false";
+        const decoded = decodeJWT<{
+          sessionToken: string;
+          cartId: number;
+          isGuest: boolean;
+        }>(cookieToken, isGuest);
+
+        if (decoded) {
+          guestCartToken = decoded.sessionToken;
+        }
+      }
+      return guestCartToken;
+  });
+  const [cartId, setCartId] = useState(() => {
+    const cookieToken = getCookie(GUEST_CART_TOKEN);
+    let guestCartId: number | null = null;
+    if (cookieToken) {
+
+      const isGuest = getCookie(IS_GUEST) !== "false";
+      const decoded = decodeJWT<{
+        sessionToken: string;
+        cartId: number;
+        isGuest: boolean;
+      }>(cookieToken, isGuest);
+
+      if (decoded) {
+        guestCartId = decoded.cartId;
+      }
+    }
+    return guestCartId;
+  });
+  // const [isReady, setIsReady] = useState(true);
 
   const isResettingRef = useRef(false);
   const tokenCreatedRef = useRef(false);
@@ -95,31 +131,11 @@ export const useGuestCartToken = () => {
     isResettingRef.current = false;
   };
 
-  useEffect(() => {
-    const cookieToken = getCookie(GUEST_CART_TOKEN);
-    console.log("cookieToken -----1 ", cookieToken);
-    if (cookieToken) {
-       console.log("cookieToken -----2 ", cookieToken);
-      const isGuest = getCookie(IS_GUEST) !== "false";
-      const decoded = decodeJWT<{
-        sessionToken: string;
-        cartId: number;
-        isGuest: boolean;
-      }>(cookieToken, isGuest);
-
-      if (decoded) {
-        setToken(decoded.sessionToken);
-        setCartId(decoded.cartId);
-      }
-    }
-
-    setIsReady(true);
-  }, []);
 
   return {
     token,
     cartId,
-    isReady,
+    // isReady,
     createGuestToken,
     resetGuestToken,
     deleteCookie,

+ 1 - 1
src/utils/hooks/useMergeCart.ts

@@ -22,7 +22,7 @@ export function useMergeCart() {
       if (cartId !== null && typeof cartId !== "undefined") {
         setCookie(GUEST_CART_ID, String(cartId));
       }
-      let cartDetail = {
+      const cartDetail = {
         id: responseData.id,
         itemsQty: responseData.itemsQty,
         taxAmount: responseData.taxAmount,

+ 2 - 2
src/utils/variantTools.ts

@@ -100,9 +100,9 @@ export function findNearestAvailableVariant(
     let res:Record<number, number> = {[fixedOptionId]: fixedValueId};
 
     for (const option of allOptions) {
-        let optionId = option.id;
+        const optionId = option.id;
         if(fixedOptionId === optionId) continue;
-        let valueId = valueIdMap[optionId];
+        const valueId = valueIdMap[optionId];
         if(isOptionValueAvailable(optionId,valueId,res,allOptions,variants)) {
             res = {...res,[optionId]: valueId};
         } else {