115 lines
2.9 KiB
TypeScript
115 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import React, { createContext, useContext, useReducer, useEffect, ReactNode } from 'react';
|
|
import { toast } from 'sonner';
|
|
import { cartReducer, getCartTotals } from '@/domain/cart/cart-domain';
|
|
import type { CartItem, NewCartItem } from '@/domain/cart/entities';
|
|
import { container } from '@/infrastructure/di/container';
|
|
import { playAddSound } from '@/infrastructure/audio/web-audio-sound-adapter';
|
|
|
|
export type { CartItem };
|
|
|
|
interface CartContextType {
|
|
items: CartItem[];
|
|
isOpen: boolean;
|
|
totalItems: number;
|
|
totalPrice: number;
|
|
addToCart: (item: NewCartItem) => void;
|
|
removeFromCart: (id: string) => void;
|
|
updateQuantity: (id: string, quantity: number) => void;
|
|
clearCart: () => void;
|
|
toggleCart: () => void;
|
|
openCart: () => void;
|
|
closeCart: () => void;
|
|
}
|
|
|
|
const CartContext = createContext<CartContextType | undefined>(undefined);
|
|
|
|
export function CartProvider({ children }: { children: ReactNode }) {
|
|
const [state, dispatch] = useReducer(cartReducer, {
|
|
items: [],
|
|
isOpen: false,
|
|
});
|
|
|
|
useEffect(() => {
|
|
const savedItems = container.cartRepository.load();
|
|
if (savedItems.length > 0) {
|
|
dispatch({ type: 'RESTORE_ITEMS', payload: savedItems });
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
container.cartRepository.save(state.items);
|
|
}, [state.items]);
|
|
|
|
const { totalItems, totalPrice } = getCartTotals(state.items);
|
|
|
|
const addToCart = (item: NewCartItem) => {
|
|
dispatch({ type: 'ADD_ITEM', payload: item });
|
|
playAddSound();
|
|
const priceLabel =
|
|
item.pricingMode === 'weight'
|
|
? `${item.pricePerHalfKg ?? item.price} kr / ½ kg`
|
|
: `${item.price} kr`;
|
|
|
|
toast.success(`Added ${item.name} to cart`, {
|
|
description: priceLabel,
|
|
action: {
|
|
label: 'View Cart',
|
|
onClick: () => dispatch({ type: 'OPEN_CART' }),
|
|
},
|
|
});
|
|
};
|
|
|
|
const removeFromCart = (id: string) => {
|
|
dispatch({ type: 'REMOVE_ITEM', payload: id });
|
|
};
|
|
|
|
const updateQuantity = (id: string, quantity: number) => {
|
|
dispatch({ type: 'UPDATE_QUANTITY', payload: { id, quantity } });
|
|
};
|
|
|
|
const clearCart = () => {
|
|
dispatch({ type: 'CLEAR_CART' });
|
|
};
|
|
|
|
const toggleCart = () => {
|
|
dispatch({ type: 'TOGGLE_CART' });
|
|
};
|
|
|
|
const openCart = () => {
|
|
dispatch({ type: 'OPEN_CART' });
|
|
};
|
|
|
|
const closeCart = () => {
|
|
dispatch({ type: 'CLOSE_CART' });
|
|
};
|
|
|
|
return (
|
|
<CartContext.Provider
|
|
value={{
|
|
items: state.items,
|
|
isOpen: state.isOpen,
|
|
totalItems,
|
|
totalPrice,
|
|
addToCart,
|
|
removeFromCart,
|
|
updateQuantity,
|
|
clearCart,
|
|
toggleCart,
|
|
openCart,
|
|
closeCart,
|
|
}}
|
|
>
|
|
{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;
|
|
} |