import { createContext, useContext, useEffect, useState } from 'react'; import { isTransientApiError } from '../api/offlineCache'; import { getHouseholdStores, getLocationZones } from '../api/stores'; import { AuthContext } from './AuthContext'; import { HouseholdContext } from './HouseholdContext'; const DEFAULT_LOCATION_NAME = "Default Location"; function getHouseholdStoreKey(store) { return String(store?.household_store_id ?? store?.store_id ?? store?.id ?? ""); } function isDefaultLocationName(store) { return store?.location_name === DEFAULT_LOCATION_NAME || store?.display_name === store?.name; } function chooseStoreLocation(locations) { if (!locations || locations.length === 0) return null; return ( locations.find(isDefaultLocationName) || locations.find((store) => store.is_default) || locations[0] ); } function chooseStoreByHouseholdStoreId(stores, householdStoreId) { const matchingLocations = stores.filter( (store) => getHouseholdStoreKey(store) === String(householdStoreId) ); return chooseStoreLocation(matchingLocations); } function getLocationStorageKey(householdId, householdStoreId) { return `activeStoreLocationId_${householdId}_${householdStoreId}`; } function chooseLocationByStoredIds(stores, householdId, householdStoreId) { const storageKey = getLocationStorageKey(householdId, householdStoreId); const savedLocationId = localStorage.getItem(storageKey); if (!savedLocationId) return null; return stores.find( (store) => String(store.id) === String(savedLocationId) && getHouseholdStoreKey(store) === String(householdStoreId) ); } export const StoreContext = createContext({ stores: [], activeStore: null, zones: [], loading: false, zonesLoading: false, error: null, setActiveStore: () => { }, refreshStores: () => { }, refreshZones: () => { }, }); export const StoreProvider = ({ children }) => { const { token } = useContext(AuthContext); const { activeHousehold } = useContext(HouseholdContext); const [stores, setStores] = useState([]); const [activeStore, setActiveStoreState] = useState(null); const [zones, setZones] = useState([]); const [loading, setLoading] = useState(false); const [zonesLoading, setZonesLoading] = useState(false); const [error, setError] = useState(null); // Load stores when household changes useEffect(() => { if (token && activeHousehold) { loadStores(); } else { // Clear state when logged out or no household setStores([]); setActiveStoreState(null); setZones([]); } }, [token, activeHousehold?.id]); // Load active store from localStorage on mount (per household) useEffect(() => { if (!activeHousehold || stores.length === 0) return; const householdStoreStorageKey = `activeHouseholdStoreId_${activeHousehold.id}`; const legacyLocationStorageKey = `activeStoreId_${activeHousehold.id}`; const savedHouseholdStoreId = localStorage.getItem(householdStoreStorageKey); if (savedHouseholdStoreId) { const store = chooseLocationByStoredIds(stores, activeHousehold.id, savedHouseholdStoreId) || chooseStoreByHouseholdStoreId(stores, savedHouseholdStoreId); if (store) { setActiveStoreState(store); return; } } const savedLocationId = localStorage.getItem(legacyLocationStorageKey); if (savedLocationId) { const savedLocation = stores.find(s => String(s.id) === String(savedLocationId)); const store = savedLocation || chooseStoreByHouseholdStoreId(stores, getHouseholdStoreKey(savedLocation)); if (store) { const householdStoreId = getHouseholdStoreKey(store); setActiveStoreState(store); localStorage.setItem(householdStoreStorageKey, householdStoreId); localStorage.setItem( getLocationStorageKey(activeHousehold.id, householdStoreId), String(store.id) ); return; } } // No saved store or not found, use the default store's representative location. const defaultStore = chooseStoreByHouseholdStoreId( stores, getHouseholdStoreKey(stores.find(s => s.is_default) || stores[0]) ); setActiveStoreState(defaultStore); const householdStoreId = getHouseholdStoreKey(defaultStore); localStorage.setItem(householdStoreStorageKey, householdStoreId); localStorage.setItem( getLocationStorageKey(activeHousehold.id, householdStoreId), String(defaultStore.id) ); }, [stores, activeHousehold]); useEffect(() => { if (token && activeHousehold?.id && activeStore?.id) { loadZones(); } else { setZones([]); } }, [token, activeHousehold?.id, activeStore?.id]); const loadStores = async () => { if (!token || !activeHousehold) return; setLoading(true); setError(null); try { const response = await getHouseholdStores(activeHousehold.id); setStores(response.data); } catch (err) { console.error('[StoreContext] Failed to load stores:', err); setError( err.response?.data?.error?.message || err.response?.data?.message || 'Failed to load stores' ); if (!isTransientApiError(err)) { setStores([]); setActiveStoreState(null); } } finally { setLoading(false); } }; const setActiveStore = (store) => { setActiveStoreState(store); if (store && activeHousehold) { const storageKey = `activeHouseholdStoreId_${activeHousehold.id}`; const householdStoreId = getHouseholdStoreKey(store); localStorage.setItem(storageKey, householdStoreId); localStorage.setItem( getLocationStorageKey(activeHousehold.id, householdStoreId), String(store.id) ); } }; const loadZones = async () => { if (!token || !activeHousehold?.id || !activeStore?.id) return; setZonesLoading(true); try { const response = await getLocationZones(activeHousehold.id, activeStore.id); setZones(response.data?.zones || []); } catch (err) { console.error('[StoreContext] Failed to load zones:', err); if (!isTransientApiError(err)) { setZones([]); } } finally { setZonesLoading(false); } }; const value = { stores, activeStore, zones, loading, zonesLoading, error, setActiveStore, refreshStores: loadStores, refreshZones: loadZones, }; return ( {children} ); };