79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
import type { CartItem } from '@irelax/types';
|
|
|
|
interface CartState {
|
|
items: CartItem[];
|
|
isCartOpen: boolean;
|
|
addToCart: (item: Omit<CartItem, 'cartItemId'>) => void;
|
|
removeFromCart: (cartItemId: string) => void;
|
|
updateQuantity: (cartItemId: string, quantity: number) => void;
|
|
clearCart: () => void;
|
|
toggleCart: (isOpen?: boolean) => void;
|
|
getCartTotal: () => number;
|
|
getCartCount: () => number;
|
|
}
|
|
|
|
export const useCartStore = create<CartState>()(
|
|
persist(
|
|
(set, get) => ({
|
|
items: [],
|
|
isCartOpen: false,
|
|
|
|
addToCart: (item) => set((state) => {
|
|
// Build a unique ID for the item. If variantId exists, use it. Otherwise, use productId.
|
|
const exactIdMatch = state.items.find(i =>
|
|
i.productId === item.productId && i.variantId === item.variantId
|
|
);
|
|
|
|
if (exactIdMatch) {
|
|
// Increment quantity if exact match exists
|
|
return {
|
|
items: state.items.map(i =>
|
|
i.cartItemId === exactIdMatch.cartItemId
|
|
? { ...i, quantity: i.quantity + item.quantity }
|
|
: i
|
|
),
|
|
isCartOpen: true
|
|
};
|
|
}
|
|
|
|
// Add new item with a generated cartItemId
|
|
const cartItemId = crypto.randomUUID();
|
|
return {
|
|
items: [...state.items, { ...item, cartItemId }],
|
|
isCartOpen: true
|
|
};
|
|
}),
|
|
|
|
removeFromCart: (cartItemId) => set((state) => ({
|
|
items: state.items.filter(i => i.cartItemId !== cartItemId)
|
|
})),
|
|
|
|
updateQuantity: (cartItemId, quantity) => set((state) => ({
|
|
items: state.items.map(i =>
|
|
i.cartItemId === cartItemId ? { ...i, quantity: Math.max(1, quantity) } : i
|
|
)
|
|
})),
|
|
|
|
clearCart: () => set({ items: [] }),
|
|
|
|
toggleCart: (isOpen) => set((state) => ({
|
|
isCartOpen: isOpen !== undefined ? isOpen : !state.isCartOpen
|
|
})),
|
|
|
|
getCartTotal: () => {
|
|
return get().items.reduce((total, item) => total + (item.price * item.quantity), 0);
|
|
},
|
|
|
|
getCartCount: () => {
|
|
return get().items.reduce((count, item) => count + item.quantity, 0);
|
|
}
|
|
}),
|
|
{
|
|
name: 'irelax-cart-storage',
|
|
partialize: (state) => ({ items: state.items }), // Only persist items, not UI state
|
|
}
|
|
)
|
|
);
|