This commit is contained in:
seb
2026-06-23 11:21:22 +02:00
parent 09f53b5ac2
commit 3009a3fb96
10 changed files with 148 additions and 35 deletions

View File

@@ -1,10 +1,12 @@
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
import { useAuth } from './auth/useAuth';
import LoginPage from './components/LoginPage';
import AppShell from './components/AppShell';
import SectionPage from './pages/SectionPage';
import { NAV_ITEMS } from './nav';
// Top-level router by auth status. Kept tiny so it rarely re-renders.
export default function App() {
const { status } = useAuth();
@@ -23,5 +25,28 @@ export default function App() {
);
}
return status === 'authed' ? <AppShell /> : <LoginPage />;
if (status !== 'authed') {
return <LoginPage />;
}
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<AppShell />}>
{NAV_ITEMS.map(({ path, label }) =>
path === '/' ? (
<Route key={path} index element={<SectionPage title={label} />} />
) : (
<Route
key={path}
path={path.slice(1)}
element={<SectionPage title={label} />}
/>
),
)}
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>
</BrowserRouter>
);
}

View File

@@ -1,21 +1,15 @@
import { useState } from 'react';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import { NavLink, Outlet } from 'react-router-dom';
import UserMenu from './UserMenu';
import { NAV_ITEMS } from '../nav';
const SIDEBAR_WIDTH = 240;
// App layout. State lives in the children (UserMenu, page content) so the
// shell itself does not re-render when their state changes.
export default function AppShell() {
const [activeId, setActiveId] = useState(NAV_ITEMS[0].id);
const activeItem = NAV_ITEMS.find((item) => item.id === activeId) ?? NAV_ITEMS[0];
const ActivePage = activeItem.Page;
return (
<Box sx={{ display: 'flex', minHeight: '100vh', bgcolor: 'grey.50' }}>
<Box
@@ -29,13 +23,17 @@ export default function AppShell() {
}}
>
<List disablePadding sx={{ flexGrow: 1 }}>
{NAV_ITEMS.map(({ id, label, icon: Icon }) => (
{NAV_ITEMS.map(({ path, label, icon: Icon }) => (
<ListItemButton
key={id}
disableGutters
selected={id === activeId}
onClick={() => setActiveId(id)}
sx={{ borderRadius: 0, px: 2 }}
key={path}
component={NavLink}
to={path}
end={path === '/'}
sx={{
borderRadius: 0,
px: 2,
'&.active': { bgcolor: 'action.selected' },
}}
>
<ListItemIcon sx={{ minWidth: 40 }}>
<Icon />
@@ -49,7 +47,7 @@ export default function AppShell() {
</Box>
<Box component="main" sx={{ flexGrow: 1, py: 4, px: 3 }}>
<ActivePage />
<Outlet />
</Box>
</Box>
);

View File

@@ -0,0 +1,13 @@
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
export default function PageLayout({ title, children }) {
return (
<Box>
<Typography variant="h5" sx={{ fontWeight: 700, mb: 2 }}>
{title}
</Typography>
{children}
</Box>
);
}

View File

@@ -1,11 +1,15 @@
import DashboardIcon from '@mui/icons-material/Dashboard';
import DashboardPage from './pages/DashboardPage';
import HomeIcon from '@mui/icons-material/Home';
import Inventory2Icon from '@mui/icons-material/Inventory2';
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
import AssignmentIcon from '@mui/icons-material/Assignment';
import PeopleIcon from '@mui/icons-material/People';
import InfoIcon from '@mui/icons-material/Info';
export const NAV_ITEMS = [
{
id: 'dashboard',
label: 'Dashboard',
icon: DashboardIcon,
Page: DashboardPage,
},
{ path: '/', label: 'Home', icon: HomeIcon },
{ path: '/artikel', label: 'Artikel', icon: Inventory2Icon },
{ path: '/lieferung', label: 'Lieferung', icon: LocalShippingIcon },
{ path: '/auftrag', label: 'Auftrag', icon: AssignmentIcon },
{ path: '/kunde', label: 'Kunde', icon: PeopleIcon },
{ path: '/infos', label: 'Infos', icon: InfoIcon },
];

View File

@@ -1,9 +0,0 @@
import Typography from '@mui/material/Typography';
export default function DashboardPage() {
return (
<Typography variant="h5" sx={{ fontWeight: 700 }}>
Dashboard
</Typography>
);
}

10
src/pages/SectionPage.jsx Normal file
View File

@@ -0,0 +1,10 @@
import Typography from '@mui/material/Typography';
import PageLayout from '../components/PageLayout';
export default function SectionPage({ title }) {
return (
<PageLayout title={title}>
<Typography color="text.secondary">Inhalt folgt.</Typography>
</PageLayout>
);
}