import React, { createContext, useContext, useEffect, useMemo, useState, useCallback } from 'react'; import { Favorite, fetchFavorites } from './favoritesApi'; import { useCustomerAuth } from './CustomerAuthContext'; interface FavoritesContextValue { favorites: Favorite[]; itemIds: Set; refresh: () => void; } const FavoritesContext = createContext({ favorites: [], itemIds: new Set(), refresh: () => {} }); export function useFavorites() { return useContext(FavoritesContext); } // Mirrors CartProvider: one fetch for the whole storefront rather than each // card asking whether it is favorited, and it clears on sign-out so one // customer's favorites never show to the next. export function FavoritesProvider({ children }: Readonly<{ children: React.ReactNode }>) { const [favorites, setFavorites] = useState([]); const { customer } = useCustomerAuth(); const refresh = useCallback(() => { fetchFavorites() .then(setFavorites) .catch(() => setFavorites([])); }, []); // Same decision as CartProvider: clearing on sign-out is synchronisation // with the session rather than derived state. See #99. useEffect(() => { if (customer) { refresh(); } else { // eslint-disable-next-line react-hooks/set-state-in-effect setFavorites([]); } }, [customer, refresh]); const itemIds = useMemo(() => new Set(favorites.map(f => f.item_id)), [favorites]); // See CartProvider: an unmemoized value re-renders every ItemCard in the // catalogue whenever anything above this provider renders. const value = useMemo(() => ({ favorites, itemIds, refresh }), [favorites, itemIds, refresh]); return ( {children} ); }