import { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { createHousehold as createHouseholdApi, getUserHouseholds, reorderHouseholds as reorderHouseholdsApi, } from '../api/households'; import { isTransientApiError } from '../api/offlineCache'; import { AuthContext } from './AuthContext'; const ACTIVE_HOUSEHOLD_STORAGE_KEY = 'activeHouseholdId'; export const HouseholdContext = createContext({ households: [], activeHousehold: null, loading: false, hasLoaded: false, error: null, setActiveHousehold: () => { }, refreshHouseholds: () => { }, createHousehold: () => { }, reorderHouseholds: () => { }, }); export const HouseholdProvider = ({ children }) => { const { token } = useContext(AuthContext); const [households, setHouseholds] = useState([]); const [activeHousehold, setActiveHouseholdState] = useState(null); const [loading, setLoading] = useState(false); const [hasLoaded, setHasLoaded] = useState(false); const [error, setError] = useState(null); const clearActiveHousehold = useCallback(() => { setActiveHouseholdState(null); localStorage.removeItem(ACTIVE_HOUSEHOLD_STORAGE_KEY); }, []); const loadHouseholds = useCallback(async () => { if (!token) return; setLoading(true); setError(null); try { const response = await getUserHouseholds(); const nextHouseholds = Array.isArray(response.data) ? response.data : []; setHouseholds(nextHouseholds); if (nextHouseholds.length === 0) { clearActiveHousehold(); } } catch (err) { console.error('[HouseholdContext] Failed to load households:', err); setError( err.response?.data?.error?.message || err.response?.data?.message || 'Failed to load households' ); if (!isTransientApiError(err)) { setHouseholds([]); clearActiveHousehold(); } } finally { setLoading(false); setHasLoaded(true); } }, [clearActiveHousehold, token]); // Load households on mount and when token changes useEffect(() => { if (token) { setHasLoaded(false); loadHouseholds(); } else { setHouseholds([]); clearActiveHousehold(); setError(null); setLoading(false); setHasLoaded(false); } }, [clearActiveHousehold, loadHouseholds, token]); // Load active household from localStorage on mount useEffect(() => { if (households.length === 0) { setActiveHouseholdState(null); return; } const savedHouseholdId = localStorage.getItem(ACTIVE_HOUSEHOLD_STORAGE_KEY); if (savedHouseholdId) { const household = households.find((candidate) => String(candidate.id) === savedHouseholdId); if (household) { setActiveHouseholdState(household); return; } } // No saved household or not found, use first one setActiveHouseholdState(households[0]); localStorage.setItem(ACTIVE_HOUSEHOLD_STORAGE_KEY, String(households[0].id)); }, [households]); const setActiveHousehold = (household) => { setActiveHouseholdState(household); if (household) { localStorage.setItem(ACTIVE_HOUSEHOLD_STORAGE_KEY, String(household.id)); } else { localStorage.removeItem(ACTIVE_HOUSEHOLD_STORAGE_KEY); } }; const createHousehold = async (name) => { try { const response = await createHouseholdApi(name); const newHousehold = response.data.household; // Refresh households list await loadHouseholds(); // Set new household as active setActiveHousehold(newHousehold); return newHousehold; } catch (err) { console.error('Failed to create household:', err); throw err; } }; const reorderHouseholds = async (orderedHouseholdIds) => { const householdById = new Map( households.map((household) => [String(household.id), household]) ); const nextHouseholds = orderedHouseholdIds .map((householdId) => householdById.get(String(householdId))) .filter(Boolean); if (nextHouseholds.length !== households.length) { throw new Error("Household order is out of date"); } const previousHouseholds = households; setHouseholds(nextHouseholds); if (activeHousehold) { const nextActiveHousehold = nextHouseholds.find( (household) => String(household.id) === String(activeHousehold.id) ); if (nextActiveHousehold) { setActiveHouseholdState(nextActiveHousehold); } } try { const response = await reorderHouseholdsApi(orderedHouseholdIds); const savedHouseholds = Array.isArray(response.data.households) ? response.data.households : []; if (savedHouseholds.length > 0) { setHouseholds(savedHouseholds); if (activeHousehold) { const savedActiveHousehold = savedHouseholds.find( (household) => String(household.id) === String(activeHousehold.id) ); if (savedActiveHousehold) { setActiveHouseholdState(savedActiveHousehold); } } } return savedHouseholds; } catch (err) { setHouseholds(previousHouseholds); if (activeHousehold) { setActiveHouseholdState(activeHousehold); } throw err; } }; const value = { households, activeHousehold, loading, hasLoaded, error, setActiveHousehold, refreshHouseholds: loadHouseholds, createHousehold, reorderHouseholds, }; return ( {children} ); };