Stripe Payment
This commit is contained in:
171
web/context/CartContext.js
Normal file
171
web/context/CartContext.js
Normal file
@@ -0,0 +1,171 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext, useState, useEffect, useCallback } from "react";
|
||||
import { useAuth } from "@/context/AuthContext";
|
||||
import {
|
||||
fetchCart,
|
||||
apiAddToCart,
|
||||
apiUpdateCartItem,
|
||||
apiRemoveCartItem,
|
||||
apiClearCart,
|
||||
apiApplyCoupon,
|
||||
apiCheckout,
|
||||
} from "@/lib/cartApi";
|
||||
|
||||
const CartContext = createContext(null);
|
||||
|
||||
const STORE_KEY = "selected_store_id";
|
||||
|
||||
export function CartProvider({ children }) {
|
||||
const { user, token } = useAuth();
|
||||
const [cart, setCart] = useState(null);
|
||||
const [selectedStoreId, setSelectedStoreIdState] = useState(null);
|
||||
const [cartLoading, setCartLoading] = useState(false);
|
||||
const [cartError, setCartError] = useState(null);
|
||||
|
||||
const setStoreId = useCallback((id) => {
|
||||
const parsed = id ? Number(id) : null;
|
||||
setSelectedStoreIdState(parsed);
|
||||
if (parsed) {
|
||||
localStorage.setItem(STORE_KEY, String(parsed));
|
||||
}
|
||||
|
||||
else {
|
||||
localStorage.removeItem(STORE_KEY);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const stored = localStorage.getItem(STORE_KEY);
|
||||
if (stored) {
|
||||
setSelectedStoreIdState(Number(stored));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const refreshCart = useCallback(async () => {
|
||||
if (!token || !selectedStoreId) {
|
||||
setCart(null);
|
||||
return;
|
||||
}
|
||||
setCartLoading(true);
|
||||
setCartError(null);
|
||||
try {
|
||||
const data = await fetchCart(token, selectedStoreId);
|
||||
setCart(data);
|
||||
}
|
||||
|
||||
catch (err) {
|
||||
setCartError(err.message);
|
||||
}
|
||||
|
||||
finally {
|
||||
setCartLoading(false);
|
||||
}
|
||||
}, [token, selectedStoreId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (user && selectedStoreId) {
|
||||
refreshCart();
|
||||
}
|
||||
|
||||
else {
|
||||
setCart(null);
|
||||
}
|
||||
}, [user, selectedStoreId, refreshCart]);
|
||||
|
||||
const addItem = useCallback(
|
||||
async (prodId, quantity = 1) => {
|
||||
if (!token || !selectedStoreId) throw new Error("Select a store first");
|
||||
const updated = await apiAddToCart(token, { prodId, storeId: selectedStoreId, quantity });
|
||||
setCart(updated);
|
||||
|
||||
return updated;
|
||||
},
|
||||
[token, selectedStoreId]
|
||||
);
|
||||
|
||||
const updateItem = useCallback(
|
||||
async (cartItemId, quantity) => {
|
||||
if (!token) return;
|
||||
const updated = await apiUpdateCartItem(token, { cartItemId, quantity });
|
||||
setCart(updated);
|
||||
|
||||
return updated;
|
||||
},
|
||||
[token]
|
||||
);
|
||||
|
||||
const removeItem = useCallback(
|
||||
async (cartItemId) => {
|
||||
if (!token) return;
|
||||
const updated = await apiRemoveCartItem(token, cartItemId);
|
||||
setCart(updated);
|
||||
|
||||
return updated;
|
||||
},
|
||||
[token]
|
||||
);
|
||||
|
||||
const clearCart = useCallback(async () => {
|
||||
if (!token || !selectedStoreId) return;
|
||||
await apiClearCart(token, selectedStoreId);
|
||||
setCart(null);
|
||||
}, [token, selectedStoreId]);
|
||||
|
||||
const applyCoupon = useCallback(
|
||||
async (couponCode) => {
|
||||
if (!token || !selectedStoreId) throw new Error("Select a store first");
|
||||
const updated = await apiApplyCoupon(token, selectedStoreId, couponCode);
|
||||
setCart(updated);
|
||||
|
||||
return updated;
|
||||
},
|
||||
[token, selectedStoreId]
|
||||
);
|
||||
|
||||
const checkout = useCallback(
|
||||
async (paymentMethodId) => {
|
||||
if (!token || !selectedStoreId) throw new Error("Select a store first");
|
||||
const result = await apiCheckout(token, {
|
||||
storeId: selectedStoreId,
|
||||
paymentMethodId,
|
||||
});
|
||||
if (result?.status === "succeeded") {
|
||||
setCart(null);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
[token, selectedStoreId]
|
||||
);
|
||||
|
||||
const itemCount = cart?.items?.reduce((sum, i) => sum + i.quantity, 0) ?? 0;
|
||||
|
||||
return (
|
||||
<CartContext.Provider
|
||||
value={{
|
||||
cart,
|
||||
cartLoading,
|
||||
cartError,
|
||||
itemCount,
|
||||
selectedStoreId,
|
||||
setStoreId,
|
||||
addItem,
|
||||
updateItem,
|
||||
removeItem,
|
||||
clearCart,
|
||||
applyCoupon,
|
||||
checkout,
|
||||
refreshCart,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</CartContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useCart() {
|
||||
const ctx = useContext(CartContext);
|
||||
if (!ctx) throw new Error("useCart must be used within a CartProvider");
|
||||
return ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user