/** * Site Selector with "All Sites" Option * Site-only selector for dashboard/overview pages * No sector selection - just sites with "All Sites" as first option */ import { useState, useEffect, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; import { Dropdown } from '../ui/dropdown/Dropdown'; import { DropdownItem } from '../ui/dropdown/DropdownItem'; import { fetchSites, Site, setActiveSite as apiSetActiveSite } from '../../services/api'; import { useToast } from '../ui/toast/ToastContainer'; import { useSiteStore } from '../../store/siteStore'; import { useAuthStore } from '../../store/authStore'; import Button from '../ui/button/Button'; interface SiteWithAllSitesSelectorProps { /** Current site filter ('all' or site id) */ siteFilter?: 'all' | number; /** Callback when site filter changes */ onSiteFilterChange?: (value: 'all' | number) => void; } export default function SiteWithAllSitesSelector({ siteFilter = 'all', onSiteFilterChange, }: SiteWithAllSitesSelectorProps) { const toast = useToast(); const navigate = useNavigate(); const { activeSite, setActiveSite, loadActiveSite } = useSiteStore(); const { user, refreshUser, isAuthenticated } = useAuthStore(); // Site switcher state const [sitesOpen, setSitesOpen] = useState(false); const [sites, setSites] = useState([]); const [sitesLoading, setSitesLoading] = useState(true); const siteButtonRef = useRef(null); const noSitesAvailable = !sitesLoading && sites.length === 0; // Load sites useEffect(() => { if (isAuthenticated && user) { refreshUser().catch((error) => { console.debug('SiteWithAllSitesSelector: Failed to refresh user (non-critical):', error); }); } }, [isAuthenticated]); useEffect(() => { loadSites(); if (!activeSite) { loadActiveSite(); } }, [user?.account?.id]); const loadSites = async () => { try { setSitesLoading(true); const response = await fetchSites(); const activeSites = (response.results || []).filter(site => site.is_active); setSites(activeSites); } catch (error: any) { console.error('Failed to load sites:', error); toast.error(`Failed to load sites: ${error.message}`); } finally { setSitesLoading(false); } }; const handleSiteSelect = async (siteId: number | 'all') => { if (onSiteFilterChange) { onSiteFilterChange(siteId); setSitesOpen(false); if (siteId !== 'all') { const selectedSite = sites.find(s => s.id === siteId); if (selectedSite) { setActiveSite(selectedSite); } } return; } // Fallback: standard site switching if (siteId === 'all') { setSitesOpen(false); return; } try { await apiSetActiveSite(siteId); const selectedSite = sites.find(s => s.id === siteId); if (selectedSite) { setActiveSite(selectedSite); toast.success(`Switched to "${selectedSite.name}"`); } setSitesOpen(false); } catch (error: any) { toast.error(`Failed to switch site: ${error.message}`); } }; // Get display text const getSiteDisplayText = () => { if (sitesLoading) return 'Loading...'; if (siteFilter === 'all') return 'All Sites'; if (typeof siteFilter === 'number') { return sites.find(s => s.id === siteFilter)?.name || activeSite?.name || 'Select Site'; } return activeSite?.name || 'All Sites'; }; // Check if a site is selected const isSiteSelected = (siteId: number | 'all') => { return siteFilter === siteId; }; const handleCreateSite = () => navigate('/sites'); if (sitesLoading && sites.length === 0) { return (
Loading sites...
); } if (noSitesAvailable) { return (
No active sites yet.
); } return (
setSitesOpen(false)} anchorRef={siteButtonRef} placement="bottom-left" className="w-64 p-2" > {/* All Sites option */} handleSiteSelect('all')} className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${ isSiteSelected('all') ? "bg-brand-50 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300" : "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300" }`} > All Sites {isSiteSelected('all') && ( )} {sites.map((site) => ( handleSiteSelect(site.id)} className={`flex items-center gap-3 px-3 py-2 font-medium rounded-lg text-sm text-left ${ isSiteSelected(site.id) ? "bg-brand-50 text-brand-700 dark:bg-brand-500/20 dark:text-brand-300" : "text-gray-700 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-white/5 dark:hover:text-gray-300" }`} > {site.name} {isSiteSelected(site.id) && ( )} ))}
); }