router
This commit is contained in:
29
src/App.jsx
29
src/App.jsx
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
13
src/components/PageLayout.jsx
Normal file
13
src/components/PageLayout.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
20
src/nav.js
20
src/nav.js
@@ -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 },
|
||||
];
|
||||
|
||||
@@ -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
10
src/pages/SectionPage.jsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user