Spaces:
Running
Running
import { createContext, useContext, useState, useEffect, ReactNode } from "react"; | |
import { CartItem } from "@/types"; | |
import { cartApi } from "@/lib/api"; | |
import { useAuth } from "./use-auth"; | |
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; | |
interface CartContextType { | |
items: CartItem[]; | |
itemCount: number; | |
subtotal: number; | |
tax: number; | |
total: number; | |
addItem: (productId: string, quantity?: number) => Promise<void>; | |
updateQuantity: (id: string, quantity: number) => Promise<void>; | |
removeItem: (id: string) => Promise<void>; | |
clearCart: () => void; | |
isLoading: boolean; | |
} | |
const CartContext = createContext<CartContextType | undefined>(undefined); | |
export function CartProvider({ children }: { children: ReactNode }) { | |
const { user, isAuthenticated } = useAuth(); | |
const queryClient = useQueryClient(); | |
const { data: items = [], isLoading } = useQuery({ | |
queryKey: ['/api/cart'], | |
queryFn: async () => { | |
if (!isAuthenticated || !user) return []; | |
const response = await cartApi.get(); | |
return response.json(); | |
}, | |
enabled: isAuthenticated && !!user, | |
}); | |
const addMutation = useMutation({ | |
mutationFn: (data: { productId: string; quantity: number }) => cartApi.add(data), | |
onSuccess: () => { | |
queryClient.invalidateQueries({ queryKey: ['/api/cart'] }); | |
}, | |
}); | |
const updateMutation = useMutation({ | |
mutationFn: ({ id, quantity }: { id: string; quantity: number }) => | |
cartApi.update(id, { quantity }), | |
onSuccess: () => { | |
queryClient.invalidateQueries({ queryKey: ['/api/cart'] }); | |
}, | |
}); | |
const removeMutation = useMutation({ | |
mutationFn: (id: string) => cartApi.remove(id), | |
onSuccess: () => { | |
queryClient.invalidateQueries({ queryKey: ['/api/cart'] }); | |
}, | |
}); | |
const addItem = async (productId: string, quantity = 1) => { | |
if (!user) return; | |
await addMutation.mutateAsync({ productId, quantity }); | |
}; | |
const updateQuantity = async (id: string, quantity: number) => { | |
await updateMutation.mutateAsync({ id, quantity }); | |
}; | |
const removeItem = async (id: string) => { | |
await removeMutation.mutateAsync(id); | |
}; | |
const clearCart = () => { | |
queryClient.setQueryData(['/api/cart'], []); | |
}; | |
const itemCount = items.reduce((count: number, item: CartItem) => count + item.quantity, 0); | |
const subtotal = items.reduce((total: number, item: CartItem) => { | |
const price = parseFloat(item.product?.price || '0'); | |
return total + (price * item.quantity); | |
}, 0); | |
const tax = subtotal * 0.08; // 8% tax | |
const total = subtotal + tax; | |
return ( | |
<CartContext.Provider value={{ | |
items, | |
itemCount, | |
subtotal, | |
tax, | |
total, | |
addItem, | |
updateQuantity, | |
removeItem, | |
clearCart, | |
isLoading, | |
}}> | |
{children} | |
</CartContext.Provider> | |
); | |
} | |
export function useCart() { | |
const context = useContext(CartContext); | |
if (context === undefined) { | |
throw new Error('useCart must be used within a CartProvider'); | |
} | |
return context; | |
} | |