Browse Source

产品详情页修改 -- 加购接口

fogwind 1 tuần trước cách đây
mục cha
commit
b2bcb344be

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

@@ -4,20 +4,27 @@ import clsx from "clsx";
 
 export function ProductAddToCart({
     isAvailable,
+    isLoading,
     onAddToCart,
     onBuyNow
 }: { 
     isAvailable: boolean; 
+    isLoading: boolean;
     onAddToCart: () => void;
     onBuyNow: () => void;
 }) { 
-
+    const btnClass = 'flex-initial flex items-center justify-center w-40 h-ly-46 rounded-4xl text-ly-16 font-bold text-white';
     return (
         <div className="fixed w-full bottom-0 left-0 bg-white box-border pt-3 pl-3 pr-3 pb-5 border-t border-solid border-ly-lightgray z-1000">
-            <div className="flex justify-between">
-                <button onClick={onBuyNow} type="button" className="flex-initial flex items-center justify-center w-40 h-ly-46 rounded-4xl text-ly-16 font-bold text-white bg-ly-deepgreen">Buy Now</button>
-                <button onClick={onAddToCart} type="button" className="flex-initial flex items-center justify-center w-40 h-ly-46 rounded-4xl text-ly-16 font-bold text-white bg-ly-middlegreen">Add To Cart</button>
-            </div>
+            {isAvailable ? (
+                <div className="flex justify-between">
+                    <button onClick={onBuyNow} type="button" className={clsx(btnClass,'bg-ly-deepgreen', { 'opacity-25':isLoading})}>Buy Now</button>
+                    <button onClick={onAddToCart} type="button" className={clsx(btnClass,'bg-ly-middlegreen', { 'opacity-25':isLoading})}>Add To Cart</button>
+                </div>
+            ): (
+                <p>The selected options are not available!</p>
+            )}
+            
         </div>
     );
 }

+ 44 - 15
src/app/(public)/product/_components/ProductInformation.tsx

@@ -9,7 +9,8 @@ import {
 import { ProductAddToCart } from "@/app/(public)/product/_components/ProductAddToCart";
 import { useCustomToast } from "@utils/hooks/useToast";
 import {clientFetch} from "@/lib/restApiClient";
-
+import { useAddProduct } from "@utils/hooks/useAddToCart";
+import { redirect, RedirectType } from 'next/navigation'
 /**
  * 辅助函数:判断一个完整的选项值ID组合是否对应一个可购买的变体(quantity > 0)
  * @param selectedIds {number[]} 选中的选项值ID的数组
@@ -138,7 +139,7 @@ export function ProductInformation({
     flexibleVariants: ResolvedVariant[];
     isSaleable: string | undefined;
 }) {
-
+    const { isCartLoading, onAddToCart } = useAddProduct();
     const { showToast } = useCustomToast();
     
     // 记录当前哪个选项组刚刚被点击(用于实现“点击组内全部可点”)
@@ -344,24 +345,51 @@ export function ProductInformation({
         }
     }
 
+    async function addProductToCart(action:string = 'addtocart') {
+        
+        let params = { 
+            productId: String(productId), 
+            quantity: productQty,
+            variantId: currentVariantInfo.variant?._id,
+        };
+        let res = await onAddToCart(params);
+        console.log('onAddToCart result --- ', res);
+        if(action === 'buynow') {
+            if(res) {
+                const responseData = res.data?.createAddProductInCart?.addProductInCart;
+                if(responseData.success) {
+                    redirect('/checkout?step=address', RedirectType.push);
+                }
+            }
+        }
+    } 
 
     let addToCartHandler = async () => {
-        // /api/test
-        // let result = await clientFetch('/api/shop/categories/1',{
-        //     method: "GET",
+   
+        // let result = await clientFetch('/api/shop/addProductInCart',{
+        //     method: "POST",
+        //     body: JSON.stringify({ productId: productId, quantity: productQty, variantId: currentVariantInfo.variant?._id }),
         // });
-        let result = await clientFetch('/api/shop/addProductInCart',{
-            method: "POST",
-            body: JSON.stringify({ productId: productId, quantity: productQty, variantId: currentVariantInfo.variant?.id }),
-        });
-        console.log(result);
-        //if(!isCurrentSelectionAvailable) {
-            // showToast("Please fill in all required fields", "warning");
-            // return;
-        //}
+        // console.log(result);
+        if(!isCurrentSelectionAvailable) {
+            showToast("The selected options are not available!", "warning");
+            return;
+        }
+
+        if(currentVariantInfo.variant && !isCartLoading) {
+            addProductToCart();
+        }
     };
 
-    let buyNowHandler = () => {};
+    let buyNowHandler = () => {
+        if(!isCurrentSelectionAvailable) {
+            showToast("The selected options are not available!", "warning");
+            return;
+        }
+        if(currentVariantInfo.variant && !isCartLoading) {
+            addProductToCart('buynow');
+        }
+    };
 
 
     return (<>
@@ -438,6 +466,7 @@ export function ProductInformation({
         </div>
         <ProductAddToCart 
             isAvailable={isCurrentSelectionAvailable} 
+            isLoading={isCartLoading}
             onAddToCart={addToCartHandler}
             onBuyNow={buyNowHandler}
         />

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

@@ -3,7 +3,7 @@
 import { useState, useEffect } from "react";
 import clsx from "clsx";
 import { StarIcon } from "@heroicons/react/24/solid";
-import { RatingTypes } from "../type";
+import { RatingTypes } from "@/components/catalog/type";
 
 
 export const AddRatingStar = ({

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

@@ -1,5 +1,5 @@
 import { IS_GUEST } from "@utils/constants";
-import { getCookie } from "@utils/getCartToken";
+import { getCookie } from "@utils/cookie-tools";
 import { useRouter } from "next/navigation";
 
 export const ReviewButton = ({ setShowForm, className }: { setShowForm: (show: boolean) => void, className?: string }) => {

+ 2 - 0
src/graphql/cart/mutations/AddProductToCart.ts

@@ -5,12 +5,14 @@ export const CREATE_ADD_PRODUCT_IN_CART = gql`
     $cartId: Int
     $productId: Int!
     $quantity: Int!
+    $variantId: Int
   ) {
     createAddProductInCart(
       input: {
         cartId: $cartId
         productId: $productId
         quantity: $quantity
+        variantId: $variantId
       }
     ) {
       addProductInCart {

+ 19 - 7
src/utils/hooks/useAddToCart.ts

@@ -2,7 +2,8 @@ import { useCustomToast } from "./useToast";
 import { useAppDispatch } from "@/store/hooks";
 import { addItem, clearCart } from "@/store/slices/cart-slice";
 import { isObject } from "@utils/type-guards";
-import { getCartToken, getCookie } from "@utils/getCartToken";
+import { getCartToken } from "@utils/getCartToken";
+import { getCookie } from "@utils/cookie-tools";
 import { useGuestCartToken } from "./useGuestCartToken";
 import { IS_GUEST } from "@/utils/constants";
 import { useMutation } from "@apollo/client";
@@ -47,14 +48,16 @@ export const useAddProduct = () => {
   const onAddToCart = async ({
     productId,
     quantity,
+    variantId
   }: {
     productId: string;
     quantity: number;
+    variantId?: number;
     token?: string;
     cartId?: number | string;
   }) => {
     // Ensure token exists - create if needed
-    let token = getCartToken();
+    let token = getCartToken(); // 从cookie获取token
 
     if (!token) {
       token = await createGuestToken();
@@ -64,13 +67,22 @@ export const useAddProduct = () => {
         return;
       }
     }
+    let param : { productId: number; quantity:number; variantId?: number; } = {
+      productId: parseInt(productId),
+      quantity,
+    };
+    if(variantId) {
+      param.variantId = variantId;
+    }
 
-    await mutateAsync({
-      variables: {
-        productId: parseInt(productId),
-        quantity,
-      },
+    let result = await mutateAsync({
+      variables: param,
     });
+
+    return {
+      data: result.data,
+      error: result.errors,
+    };
   };
 
   //--------Remove Cart Product Quantity--------//