Kansho/frontend/src/App.jsx

141 lines
4.5 KiB
React
Raw Normal View History

import { NavLink, Navigate, Outlet, Route, Routes, useLocation } from 'react-router-dom'
import { LogOut } from 'lucide-react'
import { useAuth } from './context/AuthContext.jsx'
import { getMainNavItems } from './config/appNav.js'
import LoginScreen from './pages/LoginScreen.jsx'
import SetupScreen from './pages/SetupScreen.jsx'
import HomePage from './pages/HomePage.jsx'
import PlaceholderPage from './pages/PlaceholderPage.jsx'
import DialoguePage from './pages/DialoguePage.jsx'
import SettingsPage from './pages/SettingsPage.jsx'
import AdminHomePage from './pages/AdminHomePage.jsx'
import AdminUsersPage from './pages/AdminUsersPage.jsx'
import AdminPromptsPage from './pages/AdminPromptsPage.jsx'
import AdminPlaceholdersPage from './pages/AdminPlaceholdersPage.jsx'
import AdminFeaturesPage from './pages/AdminFeaturesPage.jsx'
import AdminDialoguePage from './pages/AdminDialoguePage.jsx'
import RequireAdmin from './layouts/RequireAdmin.jsx'
import AdminShell from './layouts/AdminShell.jsx'
function navItemActive(pathname, item, routerIsActive) {
if (item.to.startsWith('/admin')) return pathname.startsWith('/admin')
return routerIsActive
}
function BottomNav({ isAdmin }) {
const items = getMainNavItems(isAdmin)
const loc = useLocation()
return (
<nav className="bottom-nav">
{items.map((item) => {
const Icon = item.icon
return (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
navItemActive(loc.pathname, item, isActive) ? 'nav-item active' : 'nav-item'
}
end={item.to === '/'}
>
<Icon size={20} />
<span>{item.label}</span>
</NavLink>
)
})}
</nav>
)
}
function DesktopSidebar({ isAdmin, onLogout, name }) {
const items = getMainNavItems(isAdmin)
const loc = useLocation()
return (
<aside className="desktop-sidebar">
<div className="brand">Kanshō</div>
<nav>
{items.map((item) => {
const Icon = item.icon
return (
<NavLink
key={item.to}
to={item.to}
className={({ isActive }) =>
navItemActive(loc.pathname, item, isActive) ? 'nav-item active' : 'nav-item'
}
end={item.to === '/'}
>
<Icon size={18} />
<span>{item.label}</span>
</NavLink>
)
})}
</nav>
<div className="sidebar-footer">
<span className="user-name">{name}</span>
<button type="button" className="ghost" onClick={onLogout}>
<LogOut size={16} /> Abmelden
</button>
</div>
</aside>
)
}
function AppShell() {
const { session, isAdmin, logout } = useAuth()
return (
<div className="app-shell">
<DesktopSidebar isAdmin={isAdmin} onLogout={logout} name={session?.profile?.name} />
<div className="app-main">
<header className="mobile-header">
<strong>Kanshō</strong>
<button type="button" className="ghost" onClick={logout}>Abmelden</button>
</header>
<main className="page">
<Outlet />
</main>
<BottomNav isAdmin={isAdmin} />
</div>
</div>
)
}
export default function App() {
const { loading, needsSetup, session } = useAuth()
if (loading) {
return <div className="centered">Lädt …</div>
}
if (needsSetup) {
return <SetupScreen />
}
if (!session) {
return <LoginScreen />
}
return (
<Routes>
<Route element={<AppShell />}>
<Route path="/" element={<HomePage />} />
<Route path="/dialog" element={<DialoguePage />} />
<Route
path="/journal"
element={<PlaceholderPage title="Journal" note="Journaling ist Werkzeug, nicht Produktkern. Die Inhalte folgen dem Fachkonzept." />}
/>
<Route path="/settings" element={<SettingsPage />} />
<Route element={<RequireAdmin />}>
<Route path="/admin" element={<AdminShell />}>
<Route index element={<AdminHomePage />} />
<Route path="users" element={<AdminUsersPage />} />
<Route path="prompts" element={<AdminPromptsPage />} />
<Route path="placeholders" element={<AdminPlaceholdersPage />} />
<Route path="features" element={<AdminFeaturesPage />} />
<Route path="dialogue" element={<AdminDialoguePage />} />
</Route>
</Route>
</Route>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
)
}