DEVELOPER REFERENCE — LIBRARY LOOT
Library Loot
Developer Reference
← Index

Source: components/AdminLayout.jsx

// src/components/AdminLayout.jsx
//
// Shell for the admin dashboard. Side nav on the left (collapses to a
// strip across the top on small screens), <Outlet /> on the right for the
// active admin sub-page. Wrap an admin route tree with this layout so the
// sub-pages don't each have to render their own nav.
//
// Created by Miguel Brown on 5/13/26.
// Copyright (c) 2026 Luckey Logic LLC. All rights reserved.

import React              from 'react'
import { NavLink, Outlet } from 'react-router-dom'

import { useAuth }        from '../context/AuthContext.jsx'

import LootButton         from './loot/LootButton.jsx'

import styles             from './AdminLayout.module.css'

const adminLinks = [
  { to: '/admin',          label: 'Overview', end: true },
  { to: '/admin/settings', label: 'Settings'            },
  { to: '/admin/books',    label: 'Books'               },
  { to: '/admin/avatars',  label: 'Avatars'             }
]

/**
 * AdminLayout — sticky-side-nav + content shell for admin pages.
 *
 * @returns {JSX.Element}
 */
export default function AdminLayout() {

  const { tenantClaim, user } = useAuth()

  return (
    <div className={styles.adminWrap}>

      <aside className={styles.sidebar} aria-label="Admin navigation">

        <div className={styles.sidebarHeader}>
          <p className={styles.eyebrow}>Admin</p>
          <p className={styles.tenant}>
            <span className={styles.tenantLabel}>Tenant</span>
            <span className={styles.tenantId}>{tenantClaim || '—'}</span>
          </p>
          {user ? (
            <p className={styles.who} title={user.email || ''}>
              Signed in as {(user.displayName && user.displayName.trim()) || user.email}
            </p>
          ) : null}
        </div>

        <nav className={styles.nav}>
          {adminLinks.map(({ to, label, end }) => (
            <NavLink
              key       ={to}
              to        ={to}
              end       ={Boolean(end)}
              className ={({ isActive }) =>
                `${styles.navLink} ${isActive ? styles.navLinkActive : ''}`
              }
            >
              {label}
            </NavLink>
          ))}
        </nav>

      </aside>

      <main className={styles.content}>
        <Outlet />
      </main>

      {/* LOOT lives at the layout root so it shows on every /admin/* route
          and never on public pages. Mounted unconditionally — the button
          itself handles open/closed state. */}
      <LootButton />

    </div>
  )
}