zhangzf il y a 11 heures
Parent
commit
aa3b479666

+ 77 - 77
src/app/(public)/customer/(has-dashboard)/order/history/_components/OrderHistory.tsx

@@ -5,80 +5,80 @@ import Link from "next/link";
 import { clientFetch } from "@/lib/restApiClient";
 
 // 模拟订单数据
-const mockOrders = [
-  {
-    id: 600217097,
-    date: "3/4/2026",
-    status: "Processing",
-    items: [
-      {
-        name: "Highlight Wigs For Women Headband Wigs with Blonde Highlights",
-        specs: "10, #022, Straight, 5 Free Headbands",
-        price: "88 points + $154.05x1",
-        image: "",
-      },
-    ],
-    progress: "Preparing Order",
-    total: "88 Points + $158.67",
-  },
-  {
-    id: 100055662,
-    date: "3/3/2026",
-    status: "Processing",
-    items: [
-      {
-        name: "Alipearl Lace Front Wig 180% Density Body Wave Human Hair Wigs Pre...",
-        specs: "10+180%, Medium, No Adjustable Band",
-        price: "$128.82x1",
-        image: "",
-      },
-    ],
-    progress: "Preparing Order",
-    total: "$132.68",
-  },
-  {
-    id: 600217055,
-    date: "3/3/2026",
-    status: "Processing",
-    items: [
-      {
-        name: "3 Bundles Deep Wave Hair With 4*4 Lace Closure Alipearl Brazilian Hair",
-        specs: "8 8 8, Free Part, 8",
-        price: "$142.14x1",
-        image: "",
-      },
-      {
-        name: "Princess Braids Wig Blonde Barbie Pre-Styled Highlight Wig 13×4 Front Wig",
-        specs: "12",
-        price: "$279.32x1",
-        image:
-          "https://cdn.alipearlhair.com/media/catalog/product/cache/6/thumbnail/750x1000/9df78eab33525d08d6e5fb8d27136e95/b/o/body_wave_lace_front_wig_2.jpg", // 替换为实际图片路径
-      },
-      {
-        name: "Deep Wave Wig 100 Human Hair Swiss Lace Wig Lace Front Wig",
-        specs: "10, Medium, 100%",
-        price: "$252.00x1",
-        image: "",
-      },
-      {
-        name: "Braids Wig Blonde Barbie Pre-Styled Highlight Wig 13×4 Front Wig",
-        specs: "12",
-        price: "6000 points + $279.32x1",
-        image:
-          "https://cdn.alipearlhair.com/media/catalog/product/cache/6/thumbnail/750x1000/9df78eab33525d08d6e5fb8d27136e95/b/o/body_wave_lace_front_wig_2.jpg", // 替换为实际图片路径
-      },
-      {
-        name: "random free wigs-2",
-        specs: "",
-        price: "$0.00x1",
-        image: "",
-      },
-    ],
-    progress: "Preparing Order",
-    discount: "-$80.00",
-    total: "$872.78",
-  },
-];
+// const mockOrders = [
+//   {
+//     id: 600217097,
+//     date: "3/4/2026",
+//     status: "Processing",
+//     items: [
+//       {
+//         name: "Highlight Wigs For Women Headband Wigs with Blonde Highlights",
+//         specs: "10, #022, Straight, 5 Free Headbands",
+//         price: "88 points + $154.05x1",
+//         image: "",
+//       },
+//     ],
+//     progress: "Preparing Order",
+//     total: "88 Points + $158.67",
+//   },
+//   {
+//     id: 100055662,
+//     date: "3/3/2026",
+//     status: "Processing",
+//     items: [
+//       {
+//         name: "Alipearl Lace Front Wig 180% Density Body Wave Human Hair Wigs Pre...",
+//         specs: "10+180%, Medium, No Adjustable Band",
+//         price: "$128.82x1",
+//         image: "",
+//       },
+//     ],
+//     progress: "Preparing Order",
+//     total: "$132.68",
+//   },
+//   {
+//     id: 600217055,
+//     date: "3/3/2026",
+//     status: "Processing",
+//     items: [
+//       {
+//         name: "3 Bundles Deep Wave Hair With 4*4 Lace Closure Alipearl Brazilian Hair",
+//         specs: "8 8 8, Free Part, 8",
+//         price: "$142.14x1",
+//         image: "",
+//       },
+//       {
+//         name: "Princess Braids Wig Blonde Barbie Pre-Styled Highlight Wig 13×4 Front Wig",
+//         specs: "12",
+//         price: "$279.32x1",
+//         image:
+//           "https://cdn.alipearlhair.com/media/catalog/product/cache/6/thumbnail/750x1000/9df78eab33525d08d6e5fb8d27136e95/b/o/body_wave_lace_front_wig_2.jpg", // 替换为实际图片路径
+//       },
+//       {
+//         name: "Deep Wave Wig 100 Human Hair Swiss Lace Wig Lace Front Wig",
+//         specs: "10, Medium, 100%",
+//         price: "$252.00x1",
+//         image: "",
+//       },
+//       {
+//         name: "Braids Wig Blonde Barbie Pre-Styled Highlight Wig 13×4 Front Wig",
+//         specs: "12",
+//         price: "6000 points + $279.32x1",
+//         image:
+//           "https://cdn.alipearlhair.com/media/catalog/product/cache/6/thumbnail/750x1000/9df78eab33525d08d6e5fb8d27136e95/b/o/body_wave_lace_front_wig_2.jpg", // 替换为实际图片路径
+//       },
+//       {
+//         name: "random free wigs-2",
+//         specs: "",
+//         price: "$0.00x1",
+//         image: "",
+//       },
+//     ],
+//     progress: "Preparing Order",
+//     discount: "-$80.00",
+//     total: "$872.78",
+//   },
+// ];
 
 // 标签列表
 const tabs = [
@@ -112,11 +112,11 @@ export default function OrderHistory() {
       const resp = await clientFetch(
         `/api/customer/orders?page=${page}&limit=${PAGE_SIZE}&status=${tabKey}`,
       );
-      let records = resp.data.records ?? [];
+      const records = resp.data ?? [];
       setTotal(resp.data.total ?? 0);
       // 模拟数据后面换成真正的接口数据
-      setTotal(100);
-      records = mockOrders; //
+      // setTotal(100);
+      // records = mockOrders; //
       if (isLoadMore) {
         setFilteredOrders((prev) => [...prev, ...records]);
       } else {

+ 2 - 2
src/app/(public)/customer/(has-dashboard)/order/view/order_id/[id]/page.tsx

@@ -18,8 +18,8 @@ type Params = {
 export default async function OrderDetail({ params }: { params: Params }) {
   // 解包拿到真实订单ID
   const realParams = await params;
-  let orderId = realParams.id;
-  orderId = '881900125';
+  const orderId = realParams.id;
+  // orderId = '881900125';
   console.log("orderId:", orderId);
 
   // 2. 服务端 fetch 请求我们自己的 Next.js API

+ 12 - 12
src/app/(public)/customer/_components/CustomerSidebar.tsx

@@ -45,10 +45,10 @@ const menus: MenuItem[] = [
   {
     name: "VIP Exclusive",
     children: [
-      {
-        name: "Level-Up Coupon",
-        path: "/customer/account/level-up-coupon",
-      },
+      // {
+      //   name: "Level-Up Coupon",
+      //   path: "/customer/account/level-up-coupon",
+      // },
       {
         name: "Birthday Reward",
         path: "/customer/account/birthday",
@@ -68,10 +68,10 @@ const menus: MenuItem[] = [
         name: "Track Order",
         path: "/track_order",
       },
-      {
-        name: "Customization Service",
-        path: "/customer/customization-service",
-      },
+      // {
+      //   name: "Customization Service",
+      //   path: "/customer/customization-service",
+      // },
     ],
   },
 
@@ -81,10 +81,10 @@ const menus: MenuItem[] = [
     path: "/customer/account/mypoints",
   },
 
-  {
-    name: "Wishlist",
-    path: "/customer/account/wishlist",
-  },
+  // {
+  //   name: "Wishlist",
+  //   path: "/customer/account/wishlist",
+  // },
 
   {
     name: "Sign Out",

+ 6 - 3
src/app/(public)/product/[urlkey]/[id]/page.tsx

@@ -27,6 +27,7 @@ import ProductDescription from "../../_components/ProductDescription";
 import { ProductDetail } from "@/app/(public)/product/_components/ProductDetail";
 import ProductText from "../../_components/ProductText";
 import { ProductInforWrapper } from "../../_components/ProductInforWrapper";
+import { auth } from "@/utils/auth/auth-helper";
 
 
 // export const dynamic = 'auto'
@@ -70,7 +71,7 @@ export async function generateMetadata({
     }
 
     return metadataRes;
-}
+}  
 
 
 //动态路由中的参数 -- params
@@ -81,7 +82,8 @@ export default async function ProductPage({
   searchParams: Promise<{ type: string }>;
 }) {
   const { urlkey } = await params;
-  
+  const session = await auth();// 游客是null
+  const isGuest = session === null;
   const resProductData = await getProductBaseInfo(urlkey);
 
   const product =  resProductData.data?.product;
@@ -163,7 +165,7 @@ export default async function ProductPage({
               <ProductMedia mediaData={mediaImgs} />
           </div>
           <div className="max-w-124">
-                <h3 className="text-ly-14 text-black  leading-ly-22">
+                <h3 className="text-ly-16 font-medium text-black  leading-ly-22">
                     {product.name}
                 </h3>
                 <ProductText productText={product.shortDescription || ""} />
@@ -171,6 +173,7 @@ export default async function ProductPage({
                 <ProductInforWrapper 
                     productBaseInfo={product}
                     optionsVariantsPromise={productOptionsRes}
+                    isGuest={isGuest}
                 />
 
                 <ShopServicePanel />

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
src/app/(public)/product/_components/InstallmentTips.tsx


+ 43 - 2
src/app/(public)/product/_components/NewUserBanner.tsx

@@ -1,8 +1,49 @@
 "use client";
+import {useLoginModal} from "@/providers/LoginModalProvider";
+import { useCustomToast } from "@/utils/hooks/useToast";
+import { confirmDialog } from "@/components/theme/ui/kernel/confirm/api";
+import { useRouter } from 'next/navigation';
+export default function NewUserBanner({isGuest}:{isGuest:boolean}) {
 
-export default function NewUserBanner() {
+   const {openLoginModal} = useLoginModal();
+   const { showToast } = useCustomToast();
+   const router = useRouter();
+    if (isGuest) return null;
+    const guestUserClick = () => {
+             openLoginModal({
+                 onFinalResult: async (res) => {
+                     if(res.mergeCartSuccess) { // 购物车合并成功
+                         // if(!res.cartAfterMerge?.isVip && res.cartAfterMerge?.vipPlusAmount === 0) {
+                         //     await switchVipPlus(true);
+                         // }
+                         return
+                     } else { // 购物车合并失败
+                         // 三种 情况: 登录成功; 注册成功;
+                         if(res.loginSuccess) {
+                             // 登录成功 需要刷新页面
+                             showToast('You have logged in successfully. But something wrong','danger');
+                             await confirmDialog({
+                                 title: "Warning",
+                                 content: "You have logged in successfully. But something wrong. You must refresh the page.",
+                                 noCancel: true,
+                             });
+                             window.location.reload();
+                         }
+                         if(res.registerSuccess && !res.loginSuccess) {
+                             // 注册成功,去登录
+                             await confirmDialog({
+                                 title: "Warning",
+                                 content: "You have registered successfully. But something wrong. You have to login.",
+                                 noCancel: true,
+                             });
+                             router.replace('/customer/login');
+                         }
+                     }
+                 }
+             });
+         };
   return (
-    <div className="w-full flex items-center justify-between mt-1 bg-[#F9F9F9] px-3 py-2 ">
+    <div onClick={guestUserClick} className="w-full flex items-center justify-between mt-1 bg-[#F9F9F9] px-3 py-2 cursor-pointer">
       {/* 左侧:用户头像SVG + 文案 */}
       <div className="flex items-center gap-2">
         {/* 用户头像绿色SVG */}

+ 2 - 2
src/app/(public)/product/_components/ProductAddToCart.tsx

@@ -29,7 +29,7 @@ export function ProductAddToCart({
           <button
             onClick={onBuyNow}
             type="button"
-            className="flex items-center justify-center rounded-full text-ly-16 font-bold text-white h-[46px] w-full mb-4 flex-1 bg-ly-deepgreen"
+            className="flex items-center justify-center rounded-full text-ly-16 font-bold text-white h-[46px] w-full mb-4 flex-1 bg-ly-deepgreen cursor-pointer"
           >
             Buy Now
           </button>
@@ -37,7 +37,7 @@ export function ProductAddToCart({
           <button
             onClick={onAddToCart}
             type="button"
-            className="flex items-center justify-center rounded-full text-ly-16 font-bold text-white h-[46px] w-full flex-1 bg-ly-middlegreen"
+            className="flex items-center justify-center rounded-full text-ly-16 font-bold text-white h-[46px] w-full flex-1 bg-ly-middlegreen cursor-pointer"
           >
             Add to Cart
           </button>

+ 5 - 3
src/app/(public)/product/_components/ProductInforWrapper.tsx

@@ -18,14 +18,16 @@ interface PriceInfo {
 
 export function ProductInforWrapper({
     productBaseInfo,
-    optionsVariantsPromise
+    optionsVariantsPromise,
+    isGuest
 }: {
     productBaseInfo: ProductBaseInfo; 
     optionsVariantsPromise: Promise<{
         err: string | null;
         productOptions: ProductOption[];
         flexibleVariants: ResolvedVariant[];
-    }>
+    }>;
+    isGuest:boolean;
 }){
 
     const productId = productBaseInfo._id;
@@ -54,7 +56,7 @@ export function ProductInforWrapper({
             </div>
 
             <InstallmentTips totalPrice={priceInfo.totalNowPrice} />
-            <NewUserBanner />
+            <NewUserBanner isGuest={isGuest} />
             {/* 产品Code */}
             <PromotionDiscountCardProps productId="product-1001" />
         </div>

+ 4 - 4
src/app/(public)/product/_components/ProductOptionsVariants.tsx

@@ -307,7 +307,7 @@ export function ProductOptionsVariants({
                                 <button key={value.id}
                                     type="button"
                                     onClick={() => !isDisabled && handleOptionClick(option.id, value.id)}
-                                    className={clsx("text-ly-16 leading-ly-24 border border-solid rounded-lg px-6 py-3 bg-white", {
+                                    className={clsx("text-ly-16 leading-ly-24 border border-solid cursor-pointer rounded-lg px-6 py-3 bg-white", {
                                         "border-ly-green text-ly-green": isSelected,
                                         "border-black text-black": !isSelected,
                                         "opacity-40 cursor-not-allowed strokeline-bg-disabled": isDisabled,
@@ -327,10 +327,10 @@ export function ProductOptionsVariants({
                 <div className="flex border border-solid rounded-lg">
                     <button onClick={() => handlerProductQty("decrease")}
                         type="button"
-                        className="flex-none w-7.5 h-11 flex items-center justify-center"
+                        className="flex-none w-7.5 h-11 flex items-center justify-center cursor-pointer "
                     >
                         <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
-                            <path stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" d="M3.33325 8L12.6666 8"/>
+                            <path stroke={productQty === 1 ? "rgba(0,0,0,0.35)" : "rgba(0, 0, 0, 1)"} strokeWidth="1.5" strokeLinejoin="round" d="M3.33325 8L12.6666 8"/>
                         </svg>
                     </button>
                     <input
@@ -341,7 +341,7 @@ export function ProductOptionsVariants({
                     />
                     <button onClick={() => handlerProductQty("increase")}
                         type="button"
-                        className="flex-none w-7.5 h-11 flex items-center justify-center"
+                        className="flex-none w-7.5 h-11 flex items-center justify-center cursor-pointer"
                     >
                         <svg className="w-4 h-4" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
                             <path stroke="rgba(0, 0, 0, 1)" strokeWidth="1.5" strokeLinejoin="round" d="M8.02026 3.3335L8.00806 12.6668"/>

+ 2 - 2
src/app/(public)/product/_components/PromotionDiscountCardProps .tsx

@@ -108,12 +108,12 @@ export default function PromotionDiscountCard({
 
         {/* 右侧优惠码 + 展开收起箭头按钮 */}
         <div className="flex items-center gap-4">
-          <span className="text-ly-14 leading-ly-22 font-bold underline">
+          <span className="text-ly-14 leading-ly-22 font-bold cursor-pointer underline">
             Code: {config.promoCode}
           </span>
           <button
             onClick={() => setIsOpen(!isOpen)}
-            className="shrink-0 transition-transform duration-300"
+            className="shrink-0 transition-transform duration-300 cursor-pointer "
             style={{ transform: isOpen ? "rotate(0deg)" : "rotate(180deg)" }}
           >
             <svg

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

@@ -12,7 +12,7 @@ export function SkeletonProductOptions() {
                     {[1,2,3,4,5,6,7,8,9,10].map((value) => {
 
                         return (
-                            <button key={value} type="button" className="h-12 w-26 rounded-lg bg-skeletonbg"></button>
+                            <button key={value} type="button" className="h-12 w-26 cursor-pointer rounded-lg bg-skeletonbg"></button>
                         );
                     })}
                 </div>

+ 2 - 0
src/app/(public)/product/_components/SwitchButton.tsx

@@ -241,6 +241,7 @@ const openGalleryModal = useCallback((
           )}
         </div>
            {/* 问答模块:固定宽度358px */}
+        { false &&
         <div className="w-[358px] shrink-0">
           <p>Q&A</p>
           <div className="h-px bg-black mt-3 mb-6"></div>
@@ -261,6 +262,7 @@ const openGalleryModal = useCallback((
             <FaqList faqList={mockFaqData} />
           )}
         </div>
+        }
       </div>
     </div>
   );

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

@@ -22,7 +22,7 @@ export default function HairPhotoGallery({
   fullReviewList.forEach((review, reviewIndex) => {
     // 这里假设图片数组是 review.attachments,按你实际字段替换
     const imgs = review.attachments || [];
-    imgs.forEach((imgSrc:string, imgIndex:number) => {
+    imgs.forEach((imgSrc:any, imgIndex:number) => {
       allImageItems.push({
         reviewIndex,
         imgIndex,

Fichier diff supprimé car celui-ci est trop grand
+ 24 - 19
src/app/(public)/product/_components/review/ReviewImageGalleryModal.tsx


+ 5 - 2
src/app/(public)/product/_components/review/ReviewModal.tsx

@@ -83,6 +83,7 @@ const ReviewModal: React.FC<ReviewModalProps> = React.memo(
   }) {
     // 全部原始评论数据(接口返回完整数据缓存)
     const [fullReviewList, setFullReviewList] = useState<ProductReviewNode[]>([]);
+    const [currentReviewTotals,setCurrentReviewTotals]  = useState<number>(reviewTotal);
     // 分页状态
     const [page, setPage] = useState(1);
     const [loading, setLoading] = useState(false);
@@ -91,7 +92,7 @@ const ReviewModal: React.FC<ReviewModalProps> = React.memo(
     const { showToast } = useCustomToast();
     // 图库弹窗状态
     // const [galleryOpen, setGalleryOpen] = useState(false);
-    const totalPage = Math.ceil(reviewTotal / PAGE_SIZE);
+    const totalPage = Math.ceil(currentReviewTotals / PAGE_SIZE);
     const [pageInputVal, setPageInputVal] = useState<string>(String(page));
     // const [galleryData, setGalleryData] = useState<{
     //   galleryList: GalleryItem[];
@@ -126,6 +127,7 @@ const ReviewModal: React.FC<ReviewModalProps> = React.memo(
             // 直接覆盖,不再追加
             setFullReviewList(res.list);
             setHasMore(pageNum * PAGE_SIZE < res.total);
+            setCurrentReviewTotals(res.total);
           } catch (err: any) {
             if (err.name !== "AbortError") {
               console.error("加载评论失败", err);
@@ -327,7 +329,7 @@ const tabLabelMap: Record<ReviewTabType, string> = {
 
             <div className="flex items-center justify-between  py-3 border-b border-gray-200 shrink-0">
             {/* 左侧 Reviews (数量) */}
-            <div className="text-xl font-medium">Reviews ({reviewTotal})</div>
+            <div className="text-xl font-medium">Reviews ({currentReviewTotals})</div>
 
             {/* 右侧下拉选择器 */}
             <div ref={dropdownRef} className="relative">
@@ -537,6 +539,7 @@ const tabLabelMap: Record<ReviewTabType, string> = {
         </div>
         {/* 图片预览弹窗 完全不变 */}
         <ReviewImageGalleryModal
+          key={galleryData.initialSlide}
           open={galleryOpen}
           onClose={galleryClose}
           galleryList={galleryData.galleryList}

+ 1 - 1
src/components/common/button/ReviewButton.tsx

@@ -8,7 +8,7 @@ export const ReviewButton = ({ setShowForm, className }: { setShowForm: (show: b
     const router = useRouter();
     const handleAddReview = async () => {
         const session = await getSession()
-        if (false&&!session) {
+        if (!session) {
             router.push("/customer/login");
         } else {
             setShowForm(true);