"use client"; import { gql } from "@apollo/client"; import { useMutation, useQuery } from "@apollo/client/react"; import { createContext, useContext, useEffect, useMemo, useState } from "react"; import { cartClient, eateryClient } from "./apollo-clients"; import { CartEntity, CartItemEntity, addMenuItemMutation, allEateriesQuery, createCartMutation, getCartQuery, } from "./types"; interface CartContextValue { items: CartItemEntity[]; totalItems: number; totalPrice: number; addToCart: (product: CartItemEntity) => void; increaseQty: (id: string) => void; decreaseQty: (id: string) => void; removeFromCart: (id: string) => void; setQuantity: (id: string, quantity: number) => void; } const CART_ID = "cartId"; const CartContext = createContext(null); const GET_CART_ITEMS = gql` query getCart($cartId: String!) { getCart(cartId: $cartId) { Id userId eateryId items { productId quantity priceAtTimeOfAdding subTotal } totalAmount paymentQrUrl } } `; const GET_EATERY = gql` query GetEateryMenu { allEateries { id } } `; const CREATE_CART = gql` mutation createCart($eateryId: String!) { createCart(eateryId: $eateryId) } `; const ADD_ITEM = gql` mutation addItem( $cartId: String! $menuItemId: String! $quantity: BigInteger! ) { addItem(cartId: $cartId, menuItemId: $menuItemId, quantity: $quantity) { Id userId eateryId items { productId quantity priceAtTimeOfAdding subTotal } totalAmount paymentQrUrl } } `; export function CartProvider({ children }: { children: React.ReactNode }) { const [cart, setCart] = useState(null!); const [cartId, setCartId] = useState(null); const { data: eateryData } = useQuery(GET_EATERY, { client: eateryClient, }); const [createCart] = useMutation(CREATE_CART, { client: cartClient, }); const { data, loading, error } = useQuery(GET_CART_ITEMS, { client: cartClient, variables: { cartId }, }); const [addMenuItem] = useMutation(ADD_ITEM, { client: cartClient, }); useEffect(() => { const createCartFunc = async () => { if (eateryData && eateryData.allEateries?.length > 0) { try { const firstEateryId = eateryData.allEateries[0].id; const { data: mutationResult } = await createCart({ variables: { eateryId: firstEateryId }, }); const newCartId = mutationResult!.createCart; if (newCartId) { localStorage.setItem(CART_ID, newCartId); setCartId(newCartId); } } catch (err) { console.error("Lỗi khi tạo giỏ hàng:", err); } } }; if (error) createCartFunc(); else { const localCartId = localStorage.getItem(CART_ID); if (localCartId) setCartId(localCartId); } }, [eateryData, createCart, data, loading, error]); useEffect(() => { if (data?.getCart) setCart(data.getCart); }, [data]); const addToCart = async (product: CartItemEntity) => { if (!cartId) return; const { data: result } = await addMenuItem({ variables: { cartId, menuItemId: product.productId!, quantity: product.quantity, }, }); if (result) setCart(result.addItem); }; const setQuantity = async (id: string, quantity: number) => { if (!cartId) return; const { data: result } = await addMenuItem({ variables: { cartId, menuItemId: id, quantity, }, }); if (result) setCart(result.addItem); }; const removeFromCart = (id: string) => setQuantity(id, 0); const increaseQty = (id: string) => setQuantity(id, cart.items.find((i) => i.productId == id)!.quantity + 1); const decreaseQty = (id: string) => setQuantity(id, cart.items.find((i) => i.productId == id)!.quantity - 1); const totalItems = useMemo( () => cart?.items.reduce((sum, item) => sum + item.quantity, 0), [cart], ); const value = useMemo( () => ({ items: cart?.items, totalItems, totalPrice: cart?.totalAmount, addToCart, increaseQty, decreaseQty, removeFromCart, setQuantity, }), [cart?.items, cart?.totalAmount], ); return {children}; } export function useCart() { const context = useContext(CartContext); if (!context) { throw new Error("useCart must be used within CartProvider"); } return context; }