wages/frontend/src/App.tsx
jtricerolph baba818693 Mobile nav: replace bottom icon bar with burger menu for consistency
Matches the slide-in sidebar + top-bar burger pattern used by other apps (maintenance, cashup) instead of the bottom tab bar.
2026-07-23 17:43:13 +00:00

95 lines
3.3 KiB
TypeScript

import { useState } from 'react'
import { DollarSign, CalendarDays, TrendingUp, BarChart3, Wallet, Settings, Menu } from 'lucide-react'
import AuthGate, { useAuth } from './components/AuthGate'
import { UpdateBanner } from './components/UpdateBanner'
import { useVersionCheck } from './hooks/useVersionCheck'
import { can } from './types'
import Weekly from './pages/Weekly'
import Monthly from './pages/Monthly'
import Rolling12Weeks from './pages/Rolling12Weeks'
import Rolling12Months from './pages/Rolling12Months'
import Budgets from './pages/Budgets'
import SettingsPage from './pages/Settings'
type Page = 'weekly' | 'monthly' | 'rolling-weeks' | 'rolling-months' | 'budgets' | 'settings'
const NAV: { id: Page; label: string; icon: React.ElementType; cap?: string }[] = [
{ id: 'weekly', label: 'Weekly', icon: CalendarDays },
{ id: 'monthly', label: 'Monthly', icon: TrendingUp },
{ id: 'rolling-weeks', label: '12 Weeks', icon: BarChart3 },
{ id: 'rolling-months', label: '12 Months', icon: BarChart3 },
{ id: 'budgets', label: 'Budgets', icon: Wallet, cap: 'budget' },
{ id: 'settings', label: 'Settings', icon: Settings, cap: 'settings' },
]
function Shell() {
const { user } = useAuth()
const [page, setPage] = useState<Page>('weekly')
const [menuOpen, setMenuOpen] = useState(false)
const hotelName = import.meta.env.VITE_HOTEL_NAME || 'Hotel'
const visibleNav = NAV.filter(n => !n.cap || can(user, n.cap))
function selectPage(id: Page) {
setPage(id)
setMenuOpen(false)
}
return (
<div className={`app-shell${menuOpen ? ' menu-open' : ''}`}>
<nav className="sidebar">
<div className="sidebar-logo">
<DollarSign size={16} strokeWidth={1.75} />
Wage Costs
</div>
<div className="sidebar-nav">
{visibleNav.map(n => (
<div
key={n.id}
className={`nav-item${page === n.id ? ' active' : ''}`}
onClick={() => selectPage(n.id)}
>
<n.icon size={16} strokeWidth={1.75} />
{n.label}
</div>
))}
</div>
<div style={{ padding: '12px 16px', fontSize: '11px', color: 'rgba(255,255,255,0.3)' }}>
{hotelName}
</div>
</nav>
{menuOpen && <div className="menu-backdrop" onClick={() => setMenuOpen(false)} />}
<header className="top-bar">
<button className="top-bar-burger" onClick={() => setMenuOpen(o => !o)}>
<Menu size={20} strokeWidth={1.75} />
</button>
<DollarSign size={18} strokeWidth={1.75} color="var(--gold)" />
<span className="top-bar-title">Wage Costs</span>
</header>
<main className="content">
{page === 'weekly' && <Weekly />}
{page === 'monthly' && <Monthly />}
{page === 'rolling-weeks' && <Rolling12Weeks />}
{page === 'rolling-months' && <Rolling12Months />}
{page === 'budgets' && <Budgets />}
{page === 'settings' && <SettingsPage />}
</main>
</div>
)
}
export default function App() {
const updateAvailable = useVersionCheck('/wages/health')
return (
<>
<AuthGate>
<Shell />
</AuthGate>
<UpdateBanner visible={updateAvailable} />
</>
)
}