File size: 3,088 Bytes
b89a86e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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;
}