diff --git a/src/app/cart/page.tsx b/src/app/cart/page.tsx index 8f3c435..1a0be7b 100644 --- a/src/app/cart/page.tsx +++ b/src/app/cart/page.tsx @@ -16,43 +16,25 @@ import { BaseURL } from '../../../utils/BaseUrl' const Cart = () => { const [timeLeft, setTimeLeft] = useState(countdownTime()); const router = useRouter() - const [cart, setCart] = useState([]) - const [token, setToken] = useState() + const { cartState, updateCart, removeFromCart } = useCart(); + const [isLoggedIn, setIsLoggedIn] = useState(false) + // Check if user is logged in useEffect(() => { - getCartData(); - }, []); + const token = localStorage.getItem('token') + setIsLoggedIn(!!token) - useEffect(() => { - const Token = localStorage.getItem('token') - setToken(Token) + // If logged in, optionally sync with API (cart is already in cartState) + if (token) { + console.log("βœ… Logged in - using CartContext (already synced)") + } else { + console.log("πŸ›’ Guest mode - using CartContext from localStorage") + } }, []) - const getCartData = async () => { - try { - const token = localStorage.getItem("token"); // should be plain token string - console.log("Stored token:", token); - - if (!token) { - console.error("❌ No token found in localStorage"); - return; - } - - const res: any = await axios.get(`${BaseURL}/cart`, { - headers: { - Authorization: `Bearer ${token}`, // must include "Bearer " - "Content-Type": "application/json", - }, - withCredentials: true, // if backend uses cookies + JWT - }); - - setCart(res?.data?.cart?.items) - console.log("Cart response βœ…:", res.data); - } catch (error: any) { - console.error("❌ Error fetching cart:", error.response?.data || error.message); - } - }; - console.log("cart", cart) + // βœ… Use cartState.cartArray as the source of truth for BOTH guest and logged-in users + const cart = cartState.cartArray; + console.log("πŸ“¦ Cart from CartContext:", cart) useEffect(() => { @@ -63,57 +45,40 @@ const Cart = () => { return () => clearInterval(timer); }, []); - const { cartState, updateCart, removeFromCart } = useCart(); - - - + // Handle quantity change for both guest and logged-in users const handleQuantityChange = async (item: any, newQuantity: number) => { if (newQuantity < 1) return; - // Optimistic Update: Update local state immediately - const updatedCart: any = cart.map((cartItem: any) => { - if (cartItem._id === item._id) { - return { ...cartItem, quantity: newQuantity }; + // Get the product ID (handle both formats) + const productId = item._id || item.id; + const size = item.selectedSize || item.size; + const color = item.selectedColor || item.color; + + // Update CartContext immediately (works for both guest and logged-in) + updateCart(productId, newQuantity, size, color); + + // If logged in, also sync with API + if (isLoggedIn) { + const token = localStorage.getItem("token"); + const payload = { + quantity: newQuantity, + color: color, + size: size + }; + + try { + await axios.put( + `${BaseURL}/cart/${productId}`, + payload, + { + headers: { Authorization: `Bearer ${token}` }, + } + ); + console.log("βœ… Cart quantity updated on API"); + } catch (error) { + console.error("❌ Error updating cart on API:", error); } - return cartItem; - }); - setCart(updatedCart); - - // Optimistic Update: Update Context (for header, etc.) - if (item.product && item.product._id) { - updateCart(item.product._id, newQuantity, item.size, item.color); } - - const payload = { - quantity: newQuantity, - color: item.color, - size: item.size - } - - const token = localStorage.getItem("token") - - try { - const res = await axios.put( - `${BaseURL}/cart/${item.product._id}`, // βœ… use product._id, not item._id - payload, - { - headers: { Authorization: `Bearer ${token}` }, - } - ) - console.log("Updated Cart:", res.data) - getCartData() - } catch (error) { - console.log("error", error) - } - - // const itemToUpdate = cart.find((item) => item._id === cart._id); - - - // // Kiểm tra xem sαΊ£n phαΊ©m cΓ³ tα»“n tαΊ‘i khΓ΄ng - // if (itemToUpdate) { - // // Truyền giΓ‘ trα»‹ hiện tαΊ‘i cα»§a selectedSize vΓ  selectedColor - // updateCart(cart._id, newQuantity, itemToUpdate.selectedSize, itemToUpdate.selectedColor); - // } }; let moneyForFreeship = 150; @@ -157,30 +122,25 @@ const Cart = () => { const handleRemoveCart = async (item: any) => { - // Optimistic update for local cart - const updatedCart = cart.filter((cartItem: any) => cartItem._id !== item._id); - setCart(updatedCart); - const token = localStorage.getItem("token"); + const productId = item._id || item.id; + const size = item.selectedSize || item.size; + const color = item.selectedColor || item.color; - // βœ… Immediately remove from CartContext (localStorage + Redux) - const cartItem = cartState.cartArray.find( - (cartItem) => (cartItem.id === item.product._id || cartItem.id === item.product.id) - ); - if (cartItem) { - removeFromCart(cartItem.id); - } + // Remove from CartContext immediately (works for both) + removeFromCart(productId); - // βœ… Then sync with API - try { - const res = await axios.delete(`${BaseURL}/cart/${item.product._id}`, { - headers: { Authorization: `Bearer ${token}` }, - params: { color: item.color, size: item.size }, // βœ… query params - }); - - getCartData(); - console.log("Removed from cart:", res.data); - } catch (error: any) { - console.error("Error removing item:", error.response?.data || error.message); + // If logged in, also sync with API + if (isLoggedIn) { + const token = localStorage.getItem("token"); + try { + await axios.delete(`${BaseURL}/cart/${productId}`, { + headers: { Authorization: `Bearer ${token}` }, + params: { color, size }, + }); + console.log("βœ… Item removed from API cart"); + } catch (error: any) { + console.error("❌ Error removing from API cart:", error.response?.data || error.message); + } } }; @@ -238,58 +198,72 @@ const Cart = () => { {cart?.length < 1 ? (

No product in cart

) : ( - cart?.map((cart: any) => ( -
-
-
-
- {cart.product.name} { + // Handle both API format (item.product.name) and CartContext format (item.name) + const itemId = item._id || item.id; + const itemName = item.product?.name || item.name; + const itemImage = item.product?.thumbImage?.[0] || item.thumbImage?.[0] || item.images?.[0]; + const itemPrice = item.price; + const itemQuantity = item.quantity || item.quantityPurchase || 1; + const itemSize = item.selectedSize || item.size || item.sizes?.[0]; + const itemColor = item.selectedColor || item.color || item.variation?.[0]?.color; + + return ( +
+
+
+
+ {itemName} +
+
+
{itemName}
+
+ Size: {itemSize} + {itemColor && Color: {itemColor}} +
+
+
+
+
+
${itemPrice}.00
+
+
+
+ { + if (itemQuantity > 1) { + handleQuantityChange(item, itemQuantity - 1) + } + }} + className={`text-base max-md:text-sm cursor-pointer ${itemQuantity === 1 ? 'opacity-50' : ''}`} + /> +
{itemQuantity}
+ handleQuantityChange(item, itemQuantity + 1)} + className='text-base max-md:text-sm cursor-pointer' />
-
-
{cart.product.name}
-
-
-
-
-
${cart.price}.00
-
-
-
- +
${itemQuantity * itemPrice}.00
+
+
+ { - if (cart.quantity > 1) { - handleQuantityChange(cart, cart.quantity - 1) - } + handleRemoveCart(item) }} - className={`text-base max-md:text-sm ${cart.quantity === 1 ? 'disabled' : ''}`} - /> -
{cart.quantity}
- handleQuantityChange(cart, cart.quantity + 1)} - className='text-base max-md:text-sm' />
-
-
${cart.quantity * cart.price}.00
-
-
- { - handleRemoveCart(cart) - }} - /> -
-
- )) + ); + }) )}
diff --git a/src/app/product/bought-together/page.tsx b/src/app/product/bought-together/page.tsx deleted file mode 100644 index 352821e..0000000 --- a/src/app/product/bought-together/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import BoughtTogether from '@/components/Product/Detail/BoughtTogether'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductBoughtTogether = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductBoughtTogether \ No newline at end of file diff --git a/src/app/product/combined-one/page.tsx b/src/app/product/combined-one/page.tsx deleted file mode 100644 index 6e4905a..0000000 --- a/src/app/product/combined-one/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import VariableProduct from '@/components/Product/Detail/VariableProduct'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductCombinedOne = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductCombinedOne \ No newline at end of file diff --git a/src/app/product/combined-two/page.tsx b/src/app/product/combined-two/page.tsx deleted file mode 100644 index cf192d6..0000000 --- a/src/app/product/combined-two/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import External from '@/components/Product/Detail/External'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductCombinedTwo = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductCombinedTwo \ No newline at end of file diff --git a/src/app/product/countdown-timer/page.tsx b/src/app/product/countdown-timer/page.tsx deleted file mode 100644 index 74b0051..0000000 --- a/src/app/product/countdown-timer/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import CountdownTimer from '@/components/Product/Detail/CountdownTimer'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductCountdownTimer = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductCountdownTimer \ No newline at end of file diff --git a/src/app/product/default/page.tsx b/src/app/product/default/page.tsx deleted file mode 100644 index a2e1f4f..0000000 --- a/src/app/product/default/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' -import React, { useState } from 'react' -import { useSearchParams } from 'next/navigation'; -import Link from 'next/link' -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Default from '@/components/Product/Detail/Default'; -import Footer from '@/components/Footer/Footer' -import { ProductType } from '@/type/ProductType' -import productData from '@/data/Product.json' - -const ProductDefault = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductDefault \ No newline at end of file diff --git a/src/app/product/discount/page.tsx b/src/app/product/discount/page.tsx deleted file mode 100644 index 0ba5f5c..0000000 --- a/src/app/product/discount/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Discount from '@/components/Product/Detail/Discount'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductDiscount = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductDiscount \ No newline at end of file diff --git a/src/app/product/external/page.tsx b/src/app/product/external/page.tsx deleted file mode 100644 index 31a6f4b..0000000 --- a/src/app/product/external/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import External from '@/components/Product/Detail/External'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductExternal = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductExternal \ No newline at end of file diff --git a/src/app/product/fixed-price/page.tsx b/src/app/product/fixed-price/page.tsx deleted file mode 100644 index f65626f..0000000 --- a/src/app/product/fixed-price/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import FixedPrice from '@/components/Product/Detail/FixedPrice'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductFixedPrice = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductFixedPrice \ No newline at end of file diff --git a/src/app/product/grouped/page.tsx b/src/app/product/grouped/page.tsx deleted file mode 100644 index 3f1a2a3..0000000 --- a/src/app/product/grouped/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Grouped from '@/components/Product/Detail/Grouped'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductGrouped = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductGrouped \ No newline at end of file diff --git a/src/app/product/on-sale/page.tsx b/src/app/product/on-sale/page.tsx deleted file mode 100644 index 2040ad0..0000000 --- a/src/app/product/on-sale/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import OnSale from '@/components/Product/Detail/OnSale'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductOnSale = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductOnSale \ No newline at end of file diff --git a/src/app/product/one-scrolling/page.tsx b/src/app/product/one-scrolling/page.tsx deleted file mode 100644 index dacebc7..0000000 --- a/src/app/product/one-scrolling/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Grouped from '@/components/Product/Detail/Grouped'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductOneScrolling = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductOneScrolling \ No newline at end of file diff --git a/src/app/product/out-of-stock/page.tsx b/src/app/product/out-of-stock/page.tsx deleted file mode 100644 index 35e549f..0000000 --- a/src/app/product/out-of-stock/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import OutOfStock from '@/components/Product/Detail/OutOfStock'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductOutOfStock = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductOutOfStock \ No newline at end of file diff --git a/src/app/product/sale/page.tsx b/src/app/product/sale/page.tsx deleted file mode 100644 index 38524b7..0000000 --- a/src/app/product/sale/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' -import React, { useState } from 'react' -import { useSearchParams } from 'next/navigation'; -import Link from 'next/link' -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Sale from '@/components/Product/Detail/Sale'; -import Footer from '@/components/Footer/Footer' -import { ProductType } from '@/type/ProductType' -import productData from '@/data/Product.json' - -const ProductSale = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductSale \ No newline at end of file diff --git a/src/app/product/sidebar/page.tsx b/src/app/product/sidebar/page.tsx deleted file mode 100644 index 927ae13..0000000 --- a/src/app/product/sidebar/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' -import React, { useState } from 'react' -import { useSearchParams } from 'next/navigation'; -import Link from 'next/link' -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Sidebar from '@/components/Product/Detail/Sidebar'; -import Footer from '@/components/Footer/Footer' -import { ProductType } from '@/type/ProductType' -import productData from '@/data/Product.json' - -const ProductSidebar = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductSidebar \ No newline at end of file diff --git a/src/app/product/styles/style1/page.tsx b/src/app/product/styles/style1/page.tsx deleted file mode 100644 index afc2175..0000000 --- a/src/app/product/styles/style1/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterCanvasProductOne() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/product/styles/style2/page.tsx b/src/app/product/styles/style2/page.tsx deleted file mode 100644 index 11dc6ed..0000000 --- a/src/app/product/styles/style2/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterCanvasProductTwo() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/product/styles/style3/page.tsx b/src/app/product/styles/style3/page.tsx deleted file mode 100644 index 4c22b26..0000000 --- a/src/app/product/styles/style3/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterCanvasProductThree() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/product/styles/style4/page.tsx b/src/app/product/styles/style4/page.tsx deleted file mode 100644 index 892e2c5..0000000 --- a/src/app/product/styles/style4/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterCanvasProductFour() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/product/styles/style5/page.tsx b/src/app/product/styles/style5/page.tsx deleted file mode 100644 index 2f4495e..0000000 --- a/src/app/product/styles/style5/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterCanvasProductFive() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/product/thumbnail-bottom/page.tsx b/src/app/product/thumbnail-bottom/page.tsx deleted file mode 100644 index 22a1638..0000000 --- a/src/app/product/thumbnail-bottom/page.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' -import React, { useState } from 'react' -import { useSearchParams } from 'next/navigation'; -import Link from 'next/link' -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Sale from '@/components/Product/Detail/Sale'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductThumbnailBottom = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductThumbnailBottom \ No newline at end of file diff --git a/src/app/product/thumbnail-left/page.tsx b/src/app/product/thumbnail-left/page.tsx deleted file mode 100644 index b78dcfc..0000000 --- a/src/app/product/thumbnail-left/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' -import React, { useState } from 'react' -import { useSearchParams } from 'next/navigation'; -import Link from 'next/link' -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import Default from '@/components/Product/Detail/Default'; -import Footer from '@/components/Footer/Footer' -import { ProductType } from '@/type/ProductType' -import productData from '@/data/Product.json' - -const ProductThumbnailLeft = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductThumbnailLeft \ No newline at end of file diff --git a/src/app/product/two-scrolling/page.tsx b/src/app/product/two-scrolling/page.tsx deleted file mode 100644 index ac76e79..0000000 --- a/src/app/product/two-scrolling/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import CountdownTimer from '@/components/Product/Detail/CountdownTimer'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductTwoScrolling = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductTwoScrolling \ No newline at end of file diff --git a/src/app/product/variable/page.tsx b/src/app/product/variable/page.tsx deleted file mode 100644 index ad9a296..0000000 --- a/src/app/product/variable/page.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' -import React from 'react' -import { useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import BreadcrumbProduct from '@/components/Breadcrumb/BreadcrumbProduct' -import VariableProduct from '@/components/Product/Detail/VariableProduct'; -import Footer from '@/components/Footer/Footer' -import productData from '@/data/Product.json' - -const ProductVariableProduct = () => { - const searchParams = useSearchParams() - let productId = searchParams.get('id') - - if (productId === null) { - productId = '1' - } - - return ( - <> - - - -
- - ) -} - -export default ProductVariableProduct \ No newline at end of file diff --git a/src/app/shop/breadcrumb-img/page.tsx b/src/app/shop/breadcrumb-img/page.tsx deleted file mode 100644 index e57d1c3..0000000 --- a/src/app/shop/breadcrumb-img/page.tsx +++ /dev/null @@ -1,61 +0,0 @@ -'use client' - -import React, { useState, useEffect } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopBreadCrumbImg from '@/components/Shop/ShopBreadCrumbImg'; -import Footer from '@/components/Footer/Footer' -import { BaseURL } from '../../../../utils/BaseUrl' -import axios from 'axios'; - -export default function BreadcrumbImg() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const categoryName = searchParams.get('category') - - const [products, setProducts] = useState([]) - const [loading, setLoading] = useState(true) - const [categories, setCategories] = useState([]) - - useEffect(() => { - fetchProducts() - getCategory() - }, []) - - const fetchProducts = async () => { - try { - const response = await axios.get(`${BaseURL}/products`) - setProducts(response?.data?.data) - setLoading(false) - } catch (error) { - console.error('Error fetching products:', error) - setLoading(false) - } - } - - - const getCategory = async () => { - try { - const res: any = await axios?.get(`${BaseURL}/categories`) - setCategories(res?.data?.data) - } catch (error) { - console.log(error) - } - } - - if (loading) { - return
Loading...
- } - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/breadcrumb1/page.tsx b/src/app/shop/breadcrumb1/page.tsx deleted file mode 100644 index d21415b..0000000 --- a/src/app/shop/breadcrumb1/page.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import React, { useState, useEffect } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopBreadCrumb1 from '@/components/Shop/ShopBreadCrumb1' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function BreadCrumb1() { - const searchParams = useSearchParams() - let [type,setType] = useState() - let datatype = searchParams.get('type') - let gender = searchParams.get('gender') - let category = searchParams.get('category') - - useEffect(() => { - setType(datatype); - }, [datatype]); - - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/breadcrumb2/page.tsx b/src/app/shop/breadcrumb2/page.tsx deleted file mode 100644 index 55eb72c..0000000 --- a/src/app/shop/breadcrumb2/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopBreadCrumb2 from '@/components/Shop/ShopBreadCrumb2' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function BreadCrumb2() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/collection/page.tsx b/src/app/shop/collection/page.tsx deleted file mode 100644 index 929c7c0..0000000 --- a/src/app/shop/collection/page.tsx +++ /dev/null @@ -1,24 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import Breadcrumb from '@/components/Breadcrumb/Breadcrumb' -import productData from '@/data/Product.json' -import ShopCollection from '@/components/Shop/ShopCollection' -import Footer from '@/components/Footer/Footer' - -export default function Collection() { - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/default-grid/page.tsx b/src/app/shop/default-grid/page.tsx deleted file mode 100644 index 2968541..0000000 --- a/src/app/shop/default-grid/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopBreadCrumb1 from '@/components/Shop/ShopBreadCrumb1' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function DefaultGrid() { - const searchParams = useSearchParams() - let type = searchParams.get('type') - let gender = searchParams.get('gender') - let category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/default-list/page.tsx b/src/app/shop/default-list/page.tsx deleted file mode 100644 index c7e5400..0000000 --- a/src/app/shop/default-list/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopSidebarList from '@/components/Shop/ShopSidebarList' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function DefaultList() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/default/page.tsx b/src/app/shop/default/page.tsx deleted file mode 100644 index ca4ba1d..0000000 --- a/src/app/shop/default/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopBreadCrumbImg from '@/components/Shop/ShopBreadCrumbImg'; -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function Default() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/fabric-customization/page.tsx b/src/app/shop/fabric-customization/page.tsx deleted file mode 100644 index f91436a..0000000 --- a/src/app/shop/fabric-customization/page.tsx +++ /dev/null @@ -1,362 +0,0 @@ -'use client'; - -import { useEffect, useRef, useState } from 'react'; -import { fabric } from 'fabric'; -import { useSearchParams } from 'next/navigation'; -import { BaseURL } from '../../../../utils/BaseUrl'; - -export default function TshirtCustomizer() { - const searchParams = useSearchParams(); - const productSlug = searchParams.get('slug'); - - const canvasRef = useRef(null); - const [shirtColor, setShirtColor] = useState('#ffffff'); - const [textInput, setTextInput] = useState(''); - const [fontFamily, setFontFamily] = useState('Arial'); - const [layers, setLayers] = useState<{ name: string; id: number }[]>([]); - const [history, setHistory] = useState([]); - const [redoStack, setRedoStack] = useState([]); - const [products, setProducts] = useState(null); - const [loading, setLoading] = useState(true); - const [shirtImageObject, setShirtImageObject] = useState(null); - - useEffect(() => { - if (productSlug) fetchProducts(); - }, [productSlug]); - - const fetchProducts = async () => { - try { - const response = await fetch(`${BaseURL}/products/slug/${productSlug}`); - const data = await response.json(); - setProducts(data?.data); - setLoading(false); - } catch (error) { - console.error('Error fetching product:', error); - setLoading(false); - } - }; - - useEffect(() => { - const canvas = new fabric.Canvas('tshirt-canvas', { - width: window.innerWidth < 500 ? 300 : 500, - height: 600, - }); - - canvasRef.current = canvas; - saveHistory(); - updateLayers(); - - canvas.on('mouse:wheel', (opt) => { - const delta = opt.e.deltaY; - let zoom = canvas.getZoom(); - zoom *= 0.999 ** delta; - zoom = Math.min(Math.max(zoom, 0.5), 2); - canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom); - opt.e.preventDefault(); - opt.e.stopPropagation(); - }); - - canvas.on('object:added', updateLayers); - canvas.on('object:removed', updateLayers); - canvas.on('object:modified', saveHistory); - canvas.on('selection:created', updateLayers); - canvas.on('selection:updated', updateLayers); - - return () => canvas.dispose(); - }, []); - - useEffect(() => { - if (products && canvasRef.current) { - const imageUrl = products?.thumbImage?.[0]; - - if (imageUrl) { - const existing = canvasRef.current - .getObjects('image') - .find((img) => (img as fabric.Image).getSrc?.() === imageUrl); - - if (!existing) { - fabric.Image.fromURL( - imageUrl, - (img) => { - img.set({ - left: 50, - top: 50, - scaleX: 0.5, - scaleY: 0.5, - selectable: false, - }); - setShirtImageObject(img); - canvasRef.current?.add(img); - canvasRef.current?.sendToBack(img); - canvasRef.current?.renderAll(); - saveHistory(); - }, - { crossOrigin: 'anonymous' } // βœ… FIXED HERE - ); - } - } - } - }, [products]); - - const applyColorFilter = (color: string) => { - const canvas = canvasRef.current; - if (!canvas || !shirtImageObject) return; - - try { - const blendColorFilter = new (fabric as any).Image.filters.BlendColor({ - color, - mode: 'tint', - alpha: 0.5, - }); - - shirtImageObject.filters = [blendColorFilter]; - shirtImageObject.applyFilters(); - canvas.renderAll(); - saveHistory(); - } catch (err) { - console.error('Color filter failed:', err); - alert('Failed to apply color filter. Make sure image is CORS-enabled.'); - } - }; - - const updateLayers = () => { - const objs = canvasRef.current?.getObjects() || []; - setLayers(objs.map((obj, i) => ({ name: obj.type + ' ' + (i + 1), id: i }))); - }; - - const saveHistory = () => { - const json = canvasRef.current?.toJSON(); - if (json) setHistory((prev) => [...prev, json.objects]); - setRedoStack([]); - }; - - const handleUndo = () => { - if (!canvasRef.current || history.length <= 1) return; - const last = history[history.length - 2]; - setRedoStack((r) => [canvasRef.current?.toJSON().objects, ...r]); - canvasRef.current.clear(); - canvasRef.current.loadFromJSON( - { objects: last }, - canvasRef.current.renderAll.bind(canvasRef.current) - ); - setHistory((h) => h.slice(0, -1)); - }; - - const handleRedo = () => { - if (!canvasRef.current || redoStack.length === 0) return; - const next = redoStack[0]; - setRedoStack((r) => r.slice(1)); - setHistory((h) => [...h, next]); - canvasRef.current.clear(); - canvasRef.current.loadFromJSON( - { objects: next }, - canvasRef.current.renderAll.bind(canvasRef.current) - ); - }; - - const handleUpload = (e: React.ChangeEvent) => { - const files = e.target.files; - if (!files || !canvasRef.current) return; - - Array.from(files).forEach((file) => { - const reader = new FileReader(); - reader.onload = () => { - if (typeof reader.result === 'string') { - fabric.Image.fromURL(reader.result, (img) => { - img.scale(0.4).set({ left: 50, top: 50 }); - canvasRef.current?.add(img); - saveHistory(); - }); - } - }; - reader.readAsDataURL(file); - }); - }; - - const addText = () => { - if (!textInput.trim() || !canvasRef.current) return; - const text = new fabric.Textbox(textInput, { - left: 100, - top: 100, - fontFamily, - fill: '#000', - fontSize: 30, - }); - canvasRef.current.add(text); - saveHistory(); - }; - - const loadTemplate = async () => { - const res = await fetch('/api/designs/my-template'); - const data = await res.json(); - if (canvasRef.current && data?.json) { - canvasRef.current.loadFromJSON( - data.json, - canvasRef.current.renderAll.bind(canvasRef.current) - ); - } - }; - - const downloadImage = () => { - const dataURL = canvasRef.current?.toDataURL({ format: 'png', quality: 1 }); - const link = document.createElement('a'); - link.href = dataURL!; - link.download = 'tshirt-design.png'; - link.click(); - }; - - const deleteObject = (index: number) => { - const obj = canvasRef.current?.getObjects()[index]; - if (obj) { - canvasRef.current?.remove(obj); - updateLayers(); - saveHistory(); - } - }; - - return ( -
-
-
-
-
-
Products Type
-
- -
-
T-shirt Color
- { setShirtColor(e.target.value); applyColorFilter(e.target.value); }} className="w-full h-10 border mb-4" /> -
- -
-
Add Text
- setTextInput(e.target.value)} className="w-full border mb-2" placeholder="Type text" /> - - -
- -
-
Upload Images
- -
- -
-
History
-
- - -
-
- -
-
Sample
-
- - -
-
- -
-
Canvas Controls
-
- - -
- -
- -
-
Object Tools
- - - - -
- -
Layers
-
    - {layers.map((layer, index) => ( -
  • - {layer.name} - -
  • - ))} -
-
- - -
- -
-
-
-
- ); -} diff --git a/src/app/shop/filter-canvas/page.tsx b/src/app/shop/filter-canvas/page.tsx deleted file mode 100644 index e8a481a..0000000 --- a/src/app/shop/filter-canvas/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterCanvas() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/filter-dropdown/page.tsx b/src/app/shop/filter-dropdown/page.tsx deleted file mode 100644 index f6b2b9a..0000000 --- a/src/app/shop/filter-dropdown/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterDropdown from '@/components/Shop/ShopFilterDropdown' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterDropdown() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/filter-options/page.tsx b/src/app/shop/filter-options/page.tsx deleted file mode 100644 index dc5cf78..0000000 --- a/src/app/shop/filter-options/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterOptions from '@/components/Shop/ShopFilterOptions' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterOptions() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/fullwidth/page.tsx b/src/app/shop/fullwidth/page.tsx deleted file mode 100644 index eb3b11d..0000000 --- a/src/app/shop/fullwidth/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterCanvas from '@/components/Shop/ShopFilterCanvas' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function Fullwidth() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/sidebar-list/page.tsx b/src/app/shop/sidebar-list/page.tsx deleted file mode 100644 index 69e5d7f..0000000 --- a/src/app/shop/sidebar-list/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopSidebarList from '@/components/Shop/ShopSidebarList' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function SidebarList() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - - -
- - ) -} diff --git a/src/app/shop/square/page.tsx b/src/app/shop/square/page.tsx deleted file mode 100644 index 8bce2ce..0000000 --- a/src/app/shop/square/page.tsx +++ /dev/null @@ -1,28 +0,0 @@ -'use client' - -import React, { useState } from 'react' -import { useRouter, useSearchParams } from 'next/navigation'; -import TopNavOne from '@/components/Header/TopNav/TopNavOne' -import MenuOne from '@/components/Header/Menu/MenuOne' -import ShopFilterDropdown from '@/components/Shop/ShopFilterDropdown' -import productData from '@/data/Product.json' -import Footer from '@/components/Footer/Footer' - -export default function FilterDropdown() { - const searchParams = useSearchParams() - const type = searchParams.get('type') - const category = searchParams.get('category') - - return ( - <> - - -
- -
-
- - ) -} diff --git a/src/components/Header/Menu/MenuOne.tsx b/src/components/Header/Menu/MenuOne.tsx index 96909d0..bbb4620 100644 --- a/src/components/Header/Menu/MenuOne.tsx +++ b/src/components/Header/Menu/MenuOne.tsx @@ -842,7 +842,7 @@ const MenuOne: React.FC = ({ props }) => {
*/} -
  • + {/*
  • = ({ props }) => { -
  • + */}
  • Blog diff --git a/src/components/Modal/ModalCart.tsx b/src/components/Modal/ModalCart.tsx index b76b532..c17b560 100644 --- a/src/components/Modal/ModalCart.tsx +++ b/src/components/Modal/ModalCart.tsx @@ -25,12 +25,13 @@ const ModalCart = ({ serverTimeLeft }: { serverTimeLeft: CountdownTimeType }) => return () => clearInterval(timer); }, []); - // Refresh cart when modal opens - useEffect(() => { - if (isModalOpen) { - refreshCart() - } - }, [isModalOpen, refreshCart]) + // Cart is already in cartState.cartArray - no need to refresh + // Removing this prevents clearing the cart when modal opens + // useEffect(() => { + // if (isModalOpen) { + // refreshCart() + // } + // }, [isModalOpen, refreshCart]) const handleRemoveFromCart = async (item: any) => { const token = localStorage.getItem("token"); diff --git a/src/components/Product/Product.tsx b/src/components/Product/Product.tsx index 977d9f6..c7b58fc 100644 --- a/src/components/Product/Product.tsx +++ b/src/components/Product/Product.tsx @@ -48,18 +48,42 @@ const Product: React.FC = ({ data, type, style }) => { const handleAddToCart = async () => { const token = localStorage.getItem("token"); // check login + + // Get the product ID (handle both _id and id) + const productId = data._id || data.id; + const payload = { - productId: data._id, - quantity: data.quantityPurchase, + productId: productId, + quantity: data.quantityPurchase || 1, color: activeColor ? activeColor : data?.variation[0]?.color, size: activeSize ? activeSize : data?.sizes[0], }; + // Create cart item with proper structure for localStorage + const cartItem = { + ...data, + id: productId, // βœ… Ensure id is set for CartContext + _id: productId, // βœ… Also set _id for consistency + quantity: payload.quantity, + selectedColor: payload.color, + selectedSize: payload.size, + quantityPurchase: payload.quantity + }; + + console.log("πŸ›’ Adding to cart:", cartItem); + console.log("πŸ“¦ Current cart:", cartState.cartArray); + // βœ… Always update Redux (works for both guest + logged-in users) - if (!cartState.cartArray.find((item) => item.id === data.id)) { - addToCart({ ...data, ...payload }); + const existingItem = cartState.cartArray.find((item) => + (item.id === productId || item._id === productId) + ); + + if (!existingItem) { + console.log("βž• Adding new item to cart"); + addToCart(cartItem); } else { - updateCart(data.id, data.quantityPurchase, payload.size, payload.color); + console.log("πŸ”„ Updating existing item"); + updateCart(productId, payload.quantity, payload.size, payload.color); } // βœ… If logged in β†’ also sync with API @@ -81,7 +105,7 @@ const Product: React.FC = ({ data, type, style }) => { ); } } else { - console.log("πŸ›’ Guest mode: cart stored only in Redux"); + console.log("πŸ›’ Guest mode: cart stored in Redux + localStorage (via CartContext)"); } openModalCart(); diff --git a/src/context/CartContext.tsx b/src/context/CartContext.tsx index b3d8453..9805f6e 100644 --- a/src/context/CartContext.tsx +++ b/src/context/CartContext.tsx @@ -10,6 +10,7 @@ interface CartItem extends ProductType { quantity: number selectedSize: string selectedColor: string + _id?: string // Support MongoDB _id format } interface CartState { @@ -65,18 +66,32 @@ const CART_KEY = 'guestCart' // Using same key for all users now const saveCartToLocalStorage = (cart: CartItem[]) => { try { + console.log("πŸ’Ύ saveCartToLocalStorage called with:", cart); localStorage.setItem(CART_KEY, JSON.stringify(cart)) + console.log("βœ… Cart saved to localStorage successfully"); } catch (error) { - console.error('Error saving cart to localStorage:', error) + console.error('❌ Error saving cart to localStorage:', error) } } const loadCartFromLocalStorage = (): CartItem[] => { try { - const cart = localStorage.getItem(CART_KEY) - return cart ? JSON.parse(cart) : [] + const cartString = localStorage.getItem(CART_KEY) + console.log("πŸ“– loadCartFromLocalStorage - Raw data:", cartString); + console.log("πŸ“– loadCartFromLocalStorage - Type:", typeof cartString); + console.log("πŸ“– loadCartFromLocalStorage - Length:", cartString?.length); + + // Check if it's the string "[]" vs actual empty + if (cartString === "[]") { + console.warn("⚠️ localStorage contains empty array string '[]'"); + } + + const cart = cartString ? JSON.parse(cartString) : [] + console.log("πŸ“– loadCartFromLocalStorage - Parsed cart:", cart); + console.log("πŸ“– loadCartFromLocalStorage - Parsed cart length:", cart.length); + return cart } catch (error) { - console.error('Error loading cart from localStorage:', error) + console.error('❌ Error loading cart from localStorage:', error) return [] } } @@ -93,12 +108,16 @@ const clearCartFromLocalStorage = () => { export const CartProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [cartState, dispatch] = useReducer(cartReducer, { cartArray: [] }) const [loading, setLoading] = useState(true) + const [isInitialLoad, setIsInitialLoad] = useState(true) const refreshCart = useCallback(async () => { // Load from localStorage for ALL users (both logged-in and guest) + console.log("πŸ”„ refreshCart called"); const cart = loadCartFromLocalStorage() + console.log("πŸ”„ refreshCart - Dispatching LOAD_CART with:", cart); dispatch({ type: 'LOAD_CART', payload: cart }) setLoading(false) + setIsInitialLoad(false) // Mark that initial load is complete }, []) // Load cart initially @@ -107,17 +126,41 @@ export const CartProvider: React.FC<{ children: React.ReactNode }> = ({ children }, [refreshCart]) // Sync cart to localStorage for ALL users whenever cartState changes + // BUT skip on initial load to prevent overwriting with empty cart useEffect(() => { - if (!loading) { + console.log("πŸ”” useEffect triggered - loading:", loading, "isInitialLoad:", isInitialLoad, "cartArray:", cartState.cartArray); + if (!loading && !isInitialLoad) { + console.log("πŸ’Ύ Calling saveCartToLocalStorage..."); saveCartToLocalStorage(cartState.cartArray) + } else { + if (loading) { + console.log("⏳ Skipping save - still loading"); + } + if (isInitialLoad) { + console.log("πŸš€ Skipping save - initial load (preventing empty cart overwrite)"); + } } - }, [cartState.cartArray, loading]) + }, [cartState.cartArray, loading, isInitialLoad]) - const addToCart = (item: CartItem) => dispatch({ type: 'ADD_TO_CART', payload: item }) - const removeFromCart = (itemId: string) => dispatch({ type: 'REMOVE_FROM_CART', payload: itemId }) - const updateCart = (itemId: string, quantity: number, selectedSize: string, selectedColor: string) => + const addToCart = (item: CartItem) => { + console.log("βž• addToCart:", item); + dispatch({ type: 'ADD_TO_CART', payload: item }) + } + + const removeFromCart = (itemId: string) => { + console.log("βž– removeFromCart:", itemId); + dispatch({ type: 'REMOVE_FROM_CART', payload: itemId }) + } + + const updateCart = (itemId: string, quantity: number, selectedSize: string, selectedColor: string) => { + console.log("πŸ”„ updateCart:", { itemId, quantity, selectedSize, selectedColor }); dispatch({ type: 'UPDATE_CART', payload: { itemId, quantity, selectedSize, selectedColor } }) - const loadCart = (items: CartItem[]) => dispatch({ type: 'LOAD_CART', payload: items }) + } + + const loadCart = (items: CartItem[]) => { + console.log("πŸ“₯ loadCart:", items); + dispatch({ type: 'LOAD_CART', payload: items }) + } const clearCart = () => { console.log("πŸ—‘οΈ Clearing cart - Redux store and localStorage"); dispatch({ type: 'CLEAR_CART' })