Initial commit: Dcorya storefront on Meshkee Website API
Next.js/TypeScript/Tailwind rebuild of dcorya.com in Persian/RTL, wired to the live Meshkee Website API for products, blog, comments, cart, and contact.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { meshkee, type Cart } from "./meshkee";
|
||||
import { useAuth } from "./auth-context";
|
||||
|
||||
type CartContextValue = {
|
||||
cart: Cart | null;
|
||||
itemCount: number;
|
||||
isLoading: boolean;
|
||||
refresh: () => Promise<void>;
|
||||
addItem: (storeItemVariantId: string, quantity?: number) => Promise<void>;
|
||||
updateItem: (itemId: string, quantity: number) => Promise<void>;
|
||||
removeItem: (itemId: string) => Promise<void>;
|
||||
};
|
||||
|
||||
const CartContext = createContext<CartContextValue | null>(null);
|
||||
|
||||
export function CartProvider({
|
||||
businessId,
|
||||
children,
|
||||
}: {
|
||||
businessId: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { accessToken } = useAuth();
|
||||
const [cart, setCart] = useState<Cart | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
if (!accessToken) {
|
||||
setCart(null);
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const { cart } = await meshkee.getCart(businessId, accessToken);
|
||||
setCart(cart);
|
||||
} catch {
|
||||
setCart(null);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [accessToken, businessId]);
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- refetch cart when auth state changes
|
||||
refresh();
|
||||
}, [refresh]);
|
||||
|
||||
const addItem = useCallback(
|
||||
async (storeItemVariantId: string, quantity = 1) => {
|
||||
if (!accessToken) return;
|
||||
const { cart } = await meshkee.addCartItem(businessId, accessToken, {
|
||||
storeItemVariantId,
|
||||
quantity,
|
||||
});
|
||||
setCart(cart);
|
||||
},
|
||||
[accessToken, businessId]
|
||||
);
|
||||
|
||||
const updateItem = useCallback(
|
||||
async (itemId: string, quantity: number) => {
|
||||
if (!accessToken) return;
|
||||
const { cart } = await meshkee.updateCartItem(businessId, accessToken, itemId, quantity);
|
||||
setCart(cart);
|
||||
},
|
||||
[accessToken, businessId]
|
||||
);
|
||||
|
||||
const removeItem = useCallback(
|
||||
async (itemId: string) => {
|
||||
if (!accessToken) return;
|
||||
const { cart } = await meshkee.removeCartItem(businessId, accessToken, itemId);
|
||||
setCart(cart);
|
||||
},
|
||||
[accessToken, businessId]
|
||||
);
|
||||
|
||||
const itemCount = useMemo(
|
||||
() => cart?.items?.reduce((sum, item) => sum + item.quantity, 0) ?? 0,
|
||||
[cart]
|
||||
);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({ cart, itemCount, isLoading, refresh, addItem, updateItem, removeItem }),
|
||||
[cart, itemCount, isLoading, refresh, addItem, updateItem, removeItem]
|
||||
);
|
||||
|
||||
return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
|
||||
}
|
||||
|
||||
export function useCart() {
|
||||
const ctx = useContext(CartContext);
|
||||
if (!ctx) throw new Error("useCart must be used within CartProvider");
|
||||
return ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user