Files
CTM-Concierge/src/App.jsx
T

66 lines
2.0 KiB
React

import { useState, useEffect, useCallback } from 'react'
import Sidebar from './components/Sidebar.jsx'
import Dashboard from './components/Dashboard.jsx'
import LiveTracking from './components/LiveTracking.jsx'
import Trips from './components/Trips.jsx'
import Records from './components/Records.jsx'
import RiskAudit from './components/RiskAudit.jsx'
import PreTravel from './components/PreTravel.jsx'
import Notifications from './components/Notifications.jsx'
import { fetchNotifications } from './lib/pocketbase.js'
/**
* App — root layout component.
* Implements a two-panel CSS Grid: fixed sidebar + scrollable main viewport.
* Owns the active-page state so sidebar navigation drives content rendering.
*/
export default function App() {
const [activePage, setActivePage] = useState('dashboard')
const [unreadNotifCount, setUnreadNotifCount] = useState(0)
const refreshUnreadCount = useCallback(async () => {
try {
const notifs = await fetchNotifications()
const unread = (notifs || []).filter((n) => !n.is_read && !n.is_archived).length
setUnreadNotifCount(unread)
} catch {
// Fallback for bridge unready or offline state
}
}, [])
useEffect(() => {
refreshUnreadCount()
}, [refreshUnreadCount, activePage])
function renderPage() {
switch (activePage) {
case 'live-tracking': return <LiveTracking />
case 'trips': return <Trips />
case 'records': return <Records />
case 'risk-audit': return <RiskAudit />
case 'pre-travel': return <PreTravel />
case 'notifications':
return (
<Notifications
onNavigate={setActivePage}
onUnreadCountChange={setUnreadNotifCount}
/>
)
default: return <Dashboard />
}
}
return (
<div className="app-shell">
<Sidebar
activePage={activePage}
onNavigate={setActivePage}
unreadNotifCount={unreadNotifCount}
/>
<main className="main-viewport">
{renderPage()}
</main>
</div>
)
}