import React from 'react'; import { NavLink } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { LayoutDashboard, CalendarDays, Sparkles, CreditCard, Settings as SettingsIcon, } from 'lucide-react'; import toast from 'react-hot-toast'; import { cn } from '@/lib/utils'; import { ADMIN_HOME_PATH, ADMIN_EVENTS_PATH, ADMIN_SETTINGS_PATH, ADMIN_BILLING_PATH, ADMIN_ENGAGEMENT_PATH, } from '../constants'; import { LanguageSwitcher } from './LanguageSwitcher'; import { registerApiErrorListener } from '../lib/apiError'; import { getDashboardSummary, getEvents, getTenantPackagesOverview } from '../api'; const navItems = [ { to: ADMIN_HOME_PATH, labelKey: 'navigation.dashboard', icon: LayoutDashboard, end: true }, { to: ADMIN_EVENTS_PATH, labelKey: 'navigation.events', icon: CalendarDays }, { to: ADMIN_ENGAGEMENT_PATH, labelKey: 'navigation.engagement', icon: Sparkles }, { to: ADMIN_BILLING_PATH, labelKey: 'navigation.billing', icon: CreditCard }, { to: ADMIN_SETTINGS_PATH, labelKey: 'navigation.settings', icon: SettingsIcon }, ]; interface AdminLayoutProps { title: string; subtitle?: string; actions?: React.ReactNode; children: React.ReactNode; } export function AdminLayout({ title, subtitle, actions, children }: AdminLayoutProps) { const { t } = useTranslation('common'); const prefetchedPathsRef = React.useRef>(new Set()); const prefetchers = React.useMemo(() => ({ [ADMIN_HOME_PATH]: () => Promise.all([ getDashboardSummary(), getEvents(), getTenantPackagesOverview(), ]).then(() => undefined), [ADMIN_EVENTS_PATH]: () => getEvents().then(() => undefined), [ADMIN_ENGAGEMENT_PATH]: () => getEvents().then(() => undefined), [ADMIN_BILLING_PATH]: () => getTenantPackagesOverview().then(() => undefined), [ADMIN_SETTINGS_PATH]: () => Promise.resolve(), }), []); const triggerPrefetch = React.useCallback( (path: string) => { if (prefetchedPathsRef.current.has(path)) { return; } const runner = prefetchers[path as keyof typeof prefetchers]; if (!runner) { return; } prefetchedPathsRef.current.add(path); Promise.resolve(runner()).catch(() => { prefetchedPathsRef.current.delete(path); }); }, [prefetchers], ); React.useEffect(() => { document.body.classList.add('tenant-admin-theme'); return () => { document.body.classList.remove('tenant-admin-theme'); }; }, []); React.useEffect(() => { const unsubscribe = registerApiErrorListener((detail) => { const fallback = t('errors.generic'); const message = detail?.message?.trim() ? detail.message : fallback; toast.error(message, { id: detail?.code ? `api-error-${detail.code}` : undefined, }); }); return unsubscribe; }, [t]); return (

{t('app.brand')}

{title}

{subtitle ?

{subtitle}

: null}
{actions}
{children}
); } function TenantMobileNav({ items, onPrefetch, }: { items: typeof navItems; onPrefetch: (path: string) => void; }) { const { t } = useTranslation('common'); return ( ); }