127 lines
4.0 KiB
TypeScript
127 lines
4.0 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import {
|
|
Container,
|
|
Box,
|
|
Fade,
|
|
} from '@mui/material';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import DashboardLayout from '../components/dashboard/DashboardLayout';
|
|
import SkeletonCard from '../components/shared/SkeletonCard';
|
|
import UserProfile from '../components/dashboard/UserProfile';
|
|
import NextcloudTalkWidget from '../components/dashboard/NextcloudTalkWidget';
|
|
import UpcomingEventsWidget from '../components/dashboard/UpcomingEventsWidget';
|
|
import AtemschutzDashboardCard from '../components/atemschutz/AtemschutzDashboardCard';
|
|
import EquipmentDashboardCard from '../components/equipment/EquipmentDashboardCard';
|
|
import VehicleDashboardCard from '../components/vehicles/VehicleDashboardCard';
|
|
import PersonalWarningsBanner from '../components/dashboard/PersonalWarningsBanner';
|
|
|
|
function Dashboard() {
|
|
const { user } = useAuth();
|
|
const canViewAtemschutz = user?.groups?.some(g =>
|
|
['dashboard_admin', 'dashboard_kommando', 'dashboard_atemschutz', 'dashboard_moderator'].includes(g)
|
|
) ?? false;
|
|
const [dataLoading, setDataLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => {
|
|
setDataLoading(false);
|
|
}, 800);
|
|
|
|
return () => clearTimeout(timer);
|
|
}, []);
|
|
|
|
return (
|
|
<DashboardLayout>
|
|
<Container maxWidth={false} disableGutters>
|
|
<Box
|
|
sx={{
|
|
display: 'grid',
|
|
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
|
|
gap: 2.5,
|
|
alignItems: 'start',
|
|
}}
|
|
>
|
|
{/* User Profile Card — full width, contains welcome greeting */}
|
|
{user && (
|
|
<Box sx={{ gridColumn: '1 / -1' }}>
|
|
{dataLoading ? (
|
|
<SkeletonCard variant="detailed" />
|
|
) : (
|
|
<Fade in={true} timeout={600} style={{ transitionDelay: '100ms' }}>
|
|
<Box>
|
|
<UserProfile user={user} />
|
|
</Box>
|
|
</Fade>
|
|
)}
|
|
</Box>
|
|
)}
|
|
|
|
{/* Personal Warnings Banner — full width, conditionally rendered */}
|
|
{user && (
|
|
<Box sx={{ gridColumn: '1 / -1' }}>
|
|
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '150ms' }}>
|
|
<Box>
|
|
<PersonalWarningsBanner user={user} />
|
|
</Box>
|
|
</Fade>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Vehicle Status Card */}
|
|
<Box>
|
|
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '300ms' }}>
|
|
<Box>
|
|
<VehicleDashboardCard />
|
|
</Box>
|
|
</Fade>
|
|
</Box>
|
|
|
|
{/* Equipment Status Card */}
|
|
<Box>
|
|
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '350ms' }}>
|
|
<Box>
|
|
<EquipmentDashboardCard />
|
|
</Box>
|
|
</Fade>
|
|
</Box>
|
|
|
|
{/* Atemschutz Status Card */}
|
|
{canViewAtemschutz && (
|
|
<Box>
|
|
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '400ms' }}>
|
|
<Box>
|
|
<AtemschutzDashboardCard />
|
|
</Box>
|
|
</Fade>
|
|
</Box>
|
|
)}
|
|
|
|
{/* Upcoming Events Widget */}
|
|
<Box>
|
|
<Fade in={!dataLoading} timeout={600} style={{ transitionDelay: '440ms' }}>
|
|
<Box>
|
|
<UpcomingEventsWidget />
|
|
</Box>
|
|
</Fade>
|
|
</Box>
|
|
|
|
{/* Nextcloud Talk Widget */}
|
|
<Box>
|
|
{dataLoading ? (
|
|
<SkeletonCard variant="basic" />
|
|
) : (
|
|
<Fade in={true} timeout={600} style={{ transitionDelay: '480ms' }}>
|
|
<Box>
|
|
<NextcloudTalkWidget />
|
|
</Box>
|
|
</Fade>
|
|
)}
|
|
</Box>
|
|
</Box>
|
|
</Container>
|
|
</DashboardLayout>
|
|
);
|
|
}
|
|
|
|
export default Dashboard;
|