import React, { createContext, useContext, useEffect, useMemo, useState, useCallback } from 'react'; import { CartItem, fetchCart } from './cartApi'; import { useCustomerAuth } from '../customer/CustomerAuthContext'; interface CartContextValue { items: CartItem[]; itemIds: Set; refresh: () => void; } const CartContext = createContext({ items: [], itemIds: new Set(), refresh: () => {} }); export function useCart() { return useContext(CartContext); } export function CartProvider({ children }: Readonly<{ children: React.ReactNode }>) { const [items, setItems] = useState([]); const { customer } = useCustomerAuth(); const refresh = useCallback(() => { fetchCart() .then(data => setItems(data.items)) .catch(() => setItems([])); }, []); // Synchronising with the session, which is an external system, so an effect // is the right tool. Deriving it instead would push "signed out" onto every // consumer of this context, and remounting on a `key` is more indirection // than the problem deserves. Decided in #99 rather than left to be // re-investigated. useEffect(() => { if (customer) { refresh(); } else { // eslint-disable-next-line react-hooks/set-state-in-effect setItems([]); } }, [customer, refresh]); const itemIds = useMemo(() => new Set(items.map(i => i.item_id)), [items]); // Memoized because this provider wraps the whole storefront: a new object // here re-renders every consumer on any parent render, cart unchanged. const value = useMemo(() => ({ items, itemIds, refresh }), [items, itemIds, refresh]); return ( {children} ); }