b37bf5d088
Release package / release (push) Successful in 4m38s
Co-authored-by: Thanh Quy - wolf <524H0124@student.tdtu.edu.vn> Co-authored-by: Thanh Quy- wolf <524H0124@student.tdtu.edu.vn> Reviewed-on: #43
208 lines
4.9 KiB
TypeScript
208 lines
4.9 KiB
TypeScript
"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;
|
|
eateryId: string | undefined;
|
|
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<CartContextValue | null>(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<CartEntity>(null!);
|
|
const [cartId, setCartId] = useState<string | null>(null);
|
|
|
|
const { data: eateryData } = useQuery<allEateriesQuery>(GET_EATERY, {
|
|
client: eateryClient,
|
|
});
|
|
|
|
const [createCart] = useMutation<createCartMutation>(CREATE_CART, {
|
|
client: cartClient,
|
|
});
|
|
|
|
const { data, loading, error } = useQuery<getCartQuery>(GET_CART_ITEMS, {
|
|
client: cartClient,
|
|
variables: { cartId },
|
|
});
|
|
|
|
const [addMenuItem] = useMutation<addMenuItemMutation>(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 if (!cartId) {
|
|
const localCartId = localStorage.getItem(CART_ID);
|
|
if (localCartId) setCartId(localCartId);
|
|
else createCartFunc();
|
|
}
|
|
}, [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, newQuantity: number) => {
|
|
if (!cartId) return;
|
|
|
|
const currentItem = cart.items.find((i) => i.productId == id);
|
|
|
|
const { data: result } = await addMenuItem({
|
|
variables: {
|
|
cartId,
|
|
menuItemId: id,
|
|
quantity: newQuantity - currentItem!.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,
|
|
eateryId: cart?.eateryId,
|
|
addToCart,
|
|
increaseQty,
|
|
decreaseQty,
|
|
removeFromCart,
|
|
setQuantity,
|
|
}),
|
|
[cart?.items, cart?.totalAmount, cart?.eateryId],
|
|
);
|
|
|
|
return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
|
|
}
|
|
|
|
export function useCart() {
|
|
const context = useContext(CartContext);
|
|
if (!context) {
|
|
throw new Error("useCart must be used within CartProvider");
|
|
}
|
|
return context;
|
|
}
|