141 lines
4.5 KiB
React
141 lines
4.5 KiB
React
|
|
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>
|
||
|
|
)
|
||
|
|
}
|