/** * Site Store (Zustand) * Manages the currently selected/active site for filtering data globally * Since Site → Sector → Keywords, and all workflows depend on Keywords/Sector, * filtering by site automatically filters all downstream data. */ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { Site, fetchSites } from '../services/api'; interface SiteState { activeSite: Site | null; loading: boolean; error: string | null; // Actions setActiveSite: (site: Site | null) => void; loadActiveSite: () => Promise; refreshActiveSite: () => Promise; } export const useSiteStore = create()( persist( (set, get) => ({ activeSite: null, loading: false, error: null, setActiveSite: (site) => { set({ activeSite: site, error: null }); // Ensure site is persisted immediately if (typeof window !== 'undefined') { try { const state = get(); localStorage.setItem('site-storage', JSON.stringify({ state: { activeSite: site }, version: 0 })); } catch (e) { console.warn('Failed to persist site to localStorage:', e); } } // Dispatch event for components to refresh data window.dispatchEvent(new CustomEvent('siteChanged', { detail: { siteId: site?.id } })); // Load sectors for the newly selected site (if sector store is available) if (site && typeof window !== 'undefined') { // Import dynamically to avoid circular dependency import('./sectorStore').then(({ useSectorStore }) => { const sectorStore = useSectorStore.getState(); sectorStore.loadSectorsForSite(site.id); }).catch(() => { // Sector store might not be available yet, that's okay }); } }, loadActiveSite: async () => { set({ loading: true, error: null }); try { const response = await fetchSites(); const allSites = response.results || []; // Find the first active site (or the one that was previously selected) const activeSites = allSites.filter(site => site.is_active); const previousSite = get().activeSite; let siteToSet: Site | null = null; if (previousSite) { // Check if previous site still exists and is accessible const previousSiteExists = allSites.find(s => s.id === previousSite.id); if (previousSiteExists && previousSiteExists.is_active) { // Keep the previously selected site if it's still active siteToSet = previousSiteExists; } else if (previousSiteExists && !previousSiteExists.is_active) { // Previous site exists but is inactive - clear it and find a new active site siteToSet = activeSites.length > 0 ? activeSites[0] : null; } else { // Previous site no longer exists - find a new active site siteToSet = activeSites.length > 0 ? activeSites[0] : null; } } else if (activeSites.length > 0) { // No previous site - use the first active site siteToSet = activeSites[0]; } set({ activeSite: siteToSet, loading: false }); // Immediately persist to localStorage for getActiveSiteId() to access if (siteToSet && typeof window !== 'undefined') { try { localStorage.setItem('site-storage', JSON.stringify({ state: { activeSite: siteToSet }, version: 0 })); } catch (e) { console.warn('Failed to persist site to localStorage:', e); } } } catch (error: any) { set({ error: error.message || 'Failed to load active site', loading: false }); } }, refreshActiveSite: async () => { const currentSite = get().activeSite; if (!currentSite) { await get().loadActiveSite(); return; } set({ loading: true, error: null }); try { const response = await fetchSites(); const updatedSite = (response.results || []).find(s => s.id === currentSite.id); if (updatedSite && updatedSite.is_active) { set({ activeSite: updatedSite, loading: false }); } else { // Current site is no longer active, load a new one await get().loadActiveSite(); } } catch (error: any) { set({ error: error.message || 'Failed to refresh active site', loading: false }); } }, }), { name: 'site-storage', partialize: (state) => ({ activeSite: state.activeSite, }), } ) );