Files
The-transit-Project/admin_ui/src/App.jsx
T

117 lines
5.2 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useEffect, useState } from 'react'
import Login from './components/Login'
import Overview from './components/Overview'
import StopsManager from './components/StopsManager'
import LinkStop from './components/LinkStop'
import BusLinesManager from './components/BusLinesManager'
import FleetManager from './components/FleetManager'
import ScheduleMaker from './components/ScheduleMaker'
import ErrorLogViewer from './components/ErrorLogViewer'
import { IconAlert, IconBus, IconCalendar, IconGrid, IconLink, IconLogout, IconMapPin, IconRoute } from './components/icons'
const SECTIONS = [
{ id: 'overview', label: 'Overzicht', eyebrow: 'Operations', title: 'Dagelijks overzicht', desc: 'Vloot, netwerk en dienstrooster in één oogopslag.', icon: IconGrid },
{ id: 'stops', label: 'Haltes', eyebrow: 'Netwerkbeheer', title: 'Haltes', desc: 'Maak herbruikbare haltes aan en bewerk ze.', icon: IconMapPin },
{ id: 'lines', label: 'Buslijnen', eyebrow: 'Netwerkbeheer', title: 'Buslijnen', desc: 'Definieer lijnen tussen start- en eindhalte.', icon: IconRoute },
{ id: 'routes', label: 'Lijnroutes', eyebrow: 'Netwerkbeheer', title: 'Stops per lijn', desc: 'Koppel haltes aan lijnen en bepaal de volgorde.', icon: IconLink },
{ id: 'fleet', label: 'Vloot', eyebrow: 'Vlootbeheer', title: 'Vloot', desc: 'Beheer de voertuigen die deel uitmaken van de vloot.', icon: IconBus },
{ id: 'schedules', label: 'Diensten', eyebrow: 'Planning', title: 'Dienstenplanning', desc: 'Plan wekelijkse schema’s en vaste diensten.', icon: IconCalendar },
{ id: 'logs', label: 'Foutmeldingen', eyebrow: 'Systeem', title: 'Centrale foutmeldingen', desc: 'Bekijk fouten die door alle diensten zijn gemeld.', icon: IconAlert },
]
const NAV_GROUPS = [
{ label: 'Algemeen', items: ['overview'] },
{ label: 'Netwerkbeheer', items: ['stops', 'lines', 'routes', 'fleet'] },
{ label: 'Planning', items: ['schedules'] },
{ label: 'Systeem', items: ['logs'] },
]
export default function App() {
const [token, setToken] = useState(localStorage.getItem('token'))
const [user, setUser] = useState(JSON.parse(localStorage.getItem('user') || 'null'))
const [section, setSection] = useState('overview')
useEffect(() => {
if (token) localStorage.setItem('token', token)
else localStorage.removeItem('token')
}, [token])
useEffect(() => {
if (user) localStorage.setItem('user', JSON.stringify(user))
else localStorage.removeItem('user')
}, [user])
if (!token) return <Login onLogin={(t, u) => { setToken(t); setUser(u); setSection('overview') }} />
const active = SECTIONS.find((s) => s.id === section) || SECTIONS[0]
const initials = (user?.name || user?.userCode || 'U').toString().slice(0, 1).toUpperCase()
return (
<div className="app-shell">
<aside className="sidebar">
<div className="brand">
<div className="brand-mark">🚌</div>
<div className="brand-text">
<div className="brand-name">Transit Ops</div>
<div className="brand-sub">Beheercentrum</div>
</div>
</div>
<nav>
{NAV_GROUPS.map((group) => (
<div key={group.label}>
<div className="nav-label">{group.label}</div>
{group.items.map((id) => {
const item = SECTIONS.find((s) => s.id === id)
const Icon = item.icon
return (
<button
key={id}
className={`nav-item ${section === id ? 'active' : ''}`}
onClick={() => setSection(id)}
>
<Icon size={18} />
<span>{item.label}</span>
</button>
)
})}
</div>
))}
</nav>
<div className="sidebar-footer">
<div className="user-chip">
<div className="user-avatar">{initials}</div>
<div className="user-meta">
<div className="user-name">{user?.name || user?.userCode || 'Gebruiker'}</div>
<div className="user-role">{user?.isAdmin ? 'Beheerder' : 'Medewerker'}</div>
</div>
<button className="logout-btn" title="Uitloggen" onClick={() => { setToken(null); setUser(null) }}>
<IconLogout size={17} />
</button>
</div>
</div>
</aside>
<div className="main">
<header className="topbar">
<div className="topbar-title">
<p className="eyebrow">{active.eyebrow}</p>
<h1>{active.title}</h1>
<p>{active.desc}</p>
</div>
</header>
<main className="content">
{section === 'overview' && <Overview token={token} user={user} />}
{section === 'stops' && <StopsManager token={token} user={user} />}
{section === 'lines' && <BusLinesManager token={token} user={user} />}
{section === 'routes' && <LinkStop token={token} user={user} />}
{section === 'fleet' && <FleetManager token={token} user={user} />}
{section === 'schedules' && <ScheduleMaker token={token} user={user} />}
{section === 'logs' && <ErrorLogViewer token={token} />}
</main>
</div>
</div>
)
}