Redesign admin UI as transit operations command center with sidebar navigation, design system, and dashboard

This commit is contained in:
Sven laptop
2026-09-24 16:54:37 +02:00
parent b766725b3b
commit 2ae1720383
16 changed files with 1905 additions and 899 deletions
+14 -20
View File
@@ -84,19 +84,22 @@ const TimetableDisplay = ({ client, overviewDate, setOverviewDate, selectedDrive
<h3>Dagelijks Overzicht</h3>
<p>Alle geplande diensten voor de geselecteerde dag</p>
</div>
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center', flexWrap: 'wrap' }}>
<input
type="date"
value={overviewDate}
onChange={e => setOverviewDate(e.target.value)}
className="no-grow"
style={{ minWidth: 150 }}
/>
<button type="button" onClick={() => setOverviewDate(new Date().toISOString().split('T')[0])}>
<button type="button" className="secondary no-grow" onClick={() => setOverviewDate(new Date().toISOString().split('T')[0])}>
Vandaag
</button>
<select
value={selectedDriverFilter}
onChange={e => setSelectedDriverFilter(e.target.value)}
style={{ padding: '6px', borderRadius: '6px', border: '1px solid #ccc' }}
className="no-grow"
style={{ minWidth: 170 }}
>
<option value="">Alle chauffeurs</option>
{drivers.map(d => (
@@ -148,46 +151,37 @@ const TimetableDisplay = ({ client, overviewDate, setOverviewDate, selectedDrive
{/* Expandable stops list */}
<button
type="button"
className="schedule-expand"
onClick={() => setExpandedSchedule(expandedSchedule === schedule.id ? null : schedule.id)}
style={{
marginTop: '0.5rem',
width: '100%',
padding: '0.4rem',
fontSize: '0.85rem',
backgroundColor: '#f0f0f0',
border: '1px solid #ddd',
borderRadius: '3px',
cursor: 'pointer',
}}
>
{expandedSchedule === schedule.id ? '▼' : '▶'} Haltes ({schedule.departureTimes?.length || 0})
</button>
{expandedSchedule === schedule.id && (
<div style={{ marginTop: '0.5rem', paddingTop: '0.5rem', borderTop: '1px solid #eee' }}>
<div style={{ marginTop: '0.5rem', paddingTop: '0.5rem', borderTop: '1px solid var(--border)' }}>
{(() => {
const lineId = schedule.busLineId
const cached = routeStopsByLine[lineId]
if (!cached) {
loadRouteStops(lineId)
return <p style={{ fontSize: '0.85rem', color: '#999' }}>Laden haltes...</p>
return <p className="faint">Laden haltes…</p>
}
if (cached.length === 0) {
return <p style={{ fontSize: '0.85rem', color: '#999' }}>Geen haltes gekoppeld</p>
return <p className="faint">Geen haltes gekoppeld</p>
}
return (
<table style={{ width: '100%', fontSize: '0.8rem' }}>
<table className="stop-table">
<tbody>
{cached.map(rs => {
const departureDate = new Date(schedule.startTime)
departureDate.setMinutes(departureDate.getMinutes() + (rs.estimatedArrivalMinutes || 0))
return (
<tr key={rs.id}>
<td style={{ paddingRight: '0.5rem' }}><strong>{rs.stopOrder}.</strong></td>
<td style={{ flex: 1 }}>{rs.name}</td>
<td style={{ textAlign: 'right', color: '#666' }}>{formatTime(departureDate.toISOString())}</td>
<td style={{ width: 24 }}><strong>{rs.stopOrder}.</strong></td>
<td>{rs.name}</td>
<td style={{ textAlign: 'right', color: 'var(--text-muted)', whiteSpace: 'nowrap' }}>{formatTime(departureDate.toISOString())}</td>
</tr>
)
})}