141 lines
4.9 KiB
TypeScript
141 lines
4.9 KiB
TypeScript
/**
|
|
* 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<void>;
|
|
refreshActiveSite: () => Promise<void>;
|
|
}
|
|
|
|
export const useSiteStore = create<SiteState>()(
|
|
persist<SiteState>(
|
|
(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,
|
|
}),
|
|
}
|
|
)
|
|
);
|
|
|