Includes: LoginPage (PIN pad), DashboardPage (30s polling table grid), OrderDetailPage (full actions), ProductsPage (CRUD + printer zone), WaitersPage (block/reset PIN/delete), TablesPage, ReportsPage (shift summary + order history + CSV export), SettingsPage (printers + test print + sysadmin lock/unlock). TailwindCSS, React Query, react-hot-toast. Docker Compose service on port 5174.
50 lines
1.7 KiB
JavaScript
50 lines
1.7 KiB
JavaScript
import { Outlet } from 'react-router-dom'
|
|
import { useState, useEffect } from 'react'
|
|
import Sidebar from '../components/Sidebar'
|
|
import useAuthStore from '../store/authStore'
|
|
import client from '../api/client'
|
|
|
|
export default function AppLayout() {
|
|
const { user, token, login, logout } = useAuthStore()
|
|
const [clock, setClock] = useState(new Date())
|
|
|
|
// Fetch user profile once on mount if token exists but user isn't loaded
|
|
useEffect(() => {
|
|
if (token && !user) {
|
|
client.get('/auth/me').then(r => login(r.data, token)).catch(() => logout())
|
|
}
|
|
}, [token])
|
|
|
|
useEffect(() => {
|
|
const id = setInterval(() => setClock(new Date()), 1000)
|
|
return () => clearInterval(id)
|
|
}, [])
|
|
|
|
const timeStr = clock.toLocaleTimeString('el-GR', { hour: '2-digit', minute: '2-digit' })
|
|
|
|
return (
|
|
<div className="flex h-screen overflow-hidden">
|
|
<Sidebar />
|
|
<div className="flex flex-col flex-1 min-w-0">
|
|
{/* Top bar */}
|
|
<header className="flex items-center justify-between px-6 py-3 bg-white border-b border-gray-200 shrink-0">
|
|
<span className="text-lg font-semibold text-gray-700 tabular-nums">{timeStr}</span>
|
|
<div className="flex items-center gap-4">
|
|
<span className="text-sm text-gray-500">{user?.username}</span>
|
|
<button
|
|
onClick={logout}
|
|
className="text-sm text-red-600 hover:text-red-800 font-medium transition-colors"
|
|
>
|
|
Αποσύνδεση
|
|
</button>
|
|
</div>
|
|
</header>
|
|
{/* Page content */}
|
|
<main className="flex-1 overflow-y-auto p-6">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|