Redesign admin UI as transit operations command center with sidebar navigation, design system, and dashboard
This commit is contained in:
+88
-25
@@ -1,15 +1,35 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
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)
|
||||
@@ -21,34 +41,77 @@ export default function App() {
|
||||
else localStorage.removeItem('user')
|
||||
}, [user])
|
||||
|
||||
if (!token) return <Login onLogin={(t,u) => { setToken(t); setUser(u); }} />
|
||||
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">
|
||||
<header className="topbar">
|
||||
<div>
|
||||
<p className="eyebrow">Transit operations</p>
|
||||
<h1>Admin control center</h1>
|
||||
<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>
|
||||
<div className="userbox">
|
||||
<strong>{user?.userCode ? `User ${user.userCode}` : 'User'}</strong>
|
||||
<button onClick={() => { setToken(null); setUser(null); }}>Logout</button>
|
||||
</div>
|
||||
</header>
|
||||
<div className="hero">
|
||||
<div>
|
||||
<h2>Fleet, lijnen en stops</h2>
|
||||
<p>Beheer haltes, buslijnen, gekoppelde stops en voertuigen vanuit één overzicht.</p>
|
||||
|
||||
<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>
|
||||
<main>
|
||||
<StopsManager token={token} user={user} />
|
||||
<BusLinesManager token={token} user={user} />
|
||||
<FleetManager token={token} user={user} />
|
||||
<LinkStop token={token} user={user} />
|
||||
<ScheduleMaker token={token} user={user} />
|
||||
<ErrorLogViewer token={token} />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user