From bd96fc032ebeba89b71aee2fbe79e85696ef68c6 Mon Sep 17 00:00:00 2001 From: Sven laptop Date: Thu, 7 May 2026 16:55:18 +0200 Subject: [PATCH] Enhance API clients with auto-logout on unauthorized responses; improve navigation and schedule handling with better error management and UI updates Co-authored-by: Copilot --- admin_ui/src/api.js | 32 +++++++++++++-- admin_ui/src/components/FleetManager.jsx | 21 ++++++++++ admin_ui/src/components/ScheduleMaker.jsx | 40 +++++++++++++------ .../lib/screens/navigation_screen.dart | 14 +++---- .../lib/screens/schedule_overview_screen.dart | 4 +- .../lib/services/navigation_service.dart | 39 ++++++++++++++++++ 6 files changed, 124 insertions(+), 26 deletions(-) diff --git a/admin_ui/src/api.js b/admin_ui/src/api.js index e09d7fd..2413a38 100644 --- a/admin_ui/src/api.js +++ b/admin_ui/src/api.js @@ -16,7 +16,31 @@ const AUTH_API = normalizeApiBaseUrl(RUNTIME.AUTH_API || import.meta.env.VITE_AU const TRANSIT_API = normalizeApiBaseUrl(RUNTIME.TRANSIT_API || import.meta.env.VITE_TRANSIT_API, 'http://localhost:5001') export const authClient = axios.create({ baseURL: AUTH_API }) -export const transitClient = (token) => axios.create({ - baseURL: TRANSIT_API, - headers: { Authorization: `Bearer ${token}` } -}) + +export const transitClient = (token) => { + const client = axios.create({ + baseURL: TRANSIT_API, + headers: { Authorization: `Bearer ${token}` } + }) + + // Auto-logout on unauthorized responses to avoid delayed failures + client.interceptors.response.use( + response => response, + error => { + try { + const status = error?.response?.status + if (status === 401 || status === 403) { + localStorage.removeItem('token') + localStorage.removeItem('user') + // reload to let App show the Login screen + if (typeof window !== 'undefined') window.location.reload() + } + } catch (e) { + // ignore + } + return Promise.reject(error) + } + ) + + return client +} diff --git a/admin_ui/src/components/FleetManager.jsx b/admin_ui/src/components/FleetManager.jsx index da88cfe..5a7d6d9 100644 --- a/admin_ui/src/components/FleetManager.jsx +++ b/admin_ui/src/components/FleetManager.jsx @@ -22,6 +22,27 @@ export default function FleetManager({ token, user }) { } } + const overlay = { + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: 'rgba(0,0,0,0.5)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + zIndex: 1000, + } + + const modal = { + backgroundColor: '#fff', + padding: '2rem', + borderRadius: '8px', + maxWidth: '400px', + boxShadow: '0 4px 12px rgba(0,0,0,0.15)', + } + useEffect(() => { loadBuses() }, []) diff --git a/admin_ui/src/components/ScheduleMaker.jsx b/admin_ui/src/components/ScheduleMaker.jsx index 6e4b5de..6b403fb 100644 --- a/admin_ui/src/components/ScheduleMaker.jsx +++ b/admin_ui/src/components/ScheduleMaker.jsx @@ -424,18 +424,34 @@ export default function ScheduleMaker({ token, user }) { {rs.name} {formatTime(departureDate.toISOString())} - { - const val = e.target.value === '' ? '' : Number(e.target.value) - setRouteStopsByLine(prev => ({ - ...prev, - [lineId]: prev[lineId].map(item => item.id === rs.id ? { ...item, estimatedArrivalMinutes: val } : item) - })) - }} - style={{ width: '5rem' }} - /> +
+ { + const val = Number(e.target.value) + setRouteStopsByLine(prev => ({ + ...prev, + [lineId]: prev[lineId].map(item => item.id === rs.id ? { ...item, estimatedArrivalMinutes: val } : item) + })) + }} + style={{ width: '8rem' }} + /> + { + const val = e.target.value === '' ? 0 : Number(e.target.value) + setRouteStopsByLine(prev => ({ + ...prev, + [lineId]: prev[lineId].map(item => item.id === rs.id ? { ...item, estimatedArrivalMinutes: val } : item) + })) + }} + style={{ width: '4.5rem' }} + /> +