import { useEffect } from 'react' import { NavLink, Outlet, useNavigate, useLocation } from 'react-router-dom' import MoonDot from '../../components/MoonDot.jsx' import { useAuth } from '../../contexts/AuthContext.jsx' import { useSite } from '../../contexts/SiteContext.jsx' // `roles` (when present) restricts which roles see a nav item. Items without it // are shown to admin/editor as before. Moderators are further confined to just // their own section + account security (see the redirect effect below). const NAV = [ { to: '/admin', label: 'Dashboard', end: true }, { to: '/admin/posts', label: 'Posts' }, { to: '/admin/wiki', label: 'Wiki' }, { to: '/admin/hero', label: 'Hero Editor' }, { to: '/admin/moderation', label: 'Moderation', roles: ['admin', 'moderator'] }, { to: '/admin/settings', label: 'Settings' }, { to: '/admin/activity', label: 'Activity' }, { to: '/admin/bot-activity', label: 'Bot Activity' }, { to: '/admin/discord-bot', label: 'Discord Bot' }, { to: '/admin/auth-providers', label: 'Authentication' }, { to: '/admin/users', label: 'Users' }, { to: '/admin/account', label: 'Account' }, ] const TITLES = { '/admin': 'Dashboard', '/admin/posts': 'Posts', '/admin/wiki': 'Wiki Pages', '/admin/hero': 'Hero Editor', '/admin/moderation': 'Moderation', '/admin/settings': 'Site Settings', '/admin/activity': 'Activity Log', '/admin/bot-activity': 'Bot Activity', '/admin/discord-bot': 'Discord Bot', '/admin/auth-providers': 'Authentication', '/admin/users': 'Users', '/admin/account': 'Account Security', } const navBtnBase = { textAlign: 'left', borderRadius: 8, padding: '10px 14px', fontFamily: 'var(--sans)', fontSize: '0.92rem', textDecoration: 'none', display: 'block', transition: 'background .15s,color .15s', } export default function AdminLayout() { const { user, logout } = useAuth() const { mode } = useSite() const navigate = useNavigate() const location = useLocation() const title = TITLES[location.pathname] || (location.pathname.startsWith('/admin/moderation') ? 'Moderation' : 'Admin') // The hero canvas editor needs room — let it use the full content width. const wide = location.pathname === '/admin/hero' const modeDot = mode === 'live' ? 'var(--mode-live)' : 'var(--mode-maint)' // Moderators only get the moderation section + their own account security. const isModerator = user?.role === 'moderator' const navItems = NAV.filter((n) => { if (n.roles && !n.roles.includes(user?.role)) return false if (isModerator) return n.to === '/admin/moderation' || n.to === '/admin/account' return true }) // Confine a moderator who deep-links (or is redirected to the index) to a page // outside their remit — the API would 403 anyway, so send them to their home. useEffect(() => { if (!isModerator) return const p = location.pathname if (!p.startsWith('/admin/moderation') && p !== '/admin/account') { navigate('/admin/moderation', { replace: true }) } }, [isModerator, location.pathname, navigate]) // Keep the admin out of search indexes (belt-and-suspenders with robots.txt). useEffect(() => { const meta = document.createElement('meta') meta.name = 'robots' meta.content = 'noindex, nofollow' document.head.appendChild(meta) return () => document.head.removeChild(meta) }, []) async function signOut() { await logout() navigate('/admin/login', { replace: true }) } return (