Files
Checkmate/client/src/components/design-elements/Fallback.tsx
T
2025-11-26 18:46:58 +00:00

177 lines
4.1 KiB
TypeScript

import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
import SkeletonCard from "@/components/design-elements/SkeletonCard";
import Typography from "@mui/material/Typography";
import { BulletPointCheck } from "@/components/design-elements";
import { Button } from "@/components/inputs";
import { useNavigate } from "react-router";
import useMediaQuery from "@mui/material/useMediaQuery";
import { useTheme } from "@mui/material/styles";
import type { StackProps } from "@mui/material/Stack";
interface BaseFallbackProps extends StackProps {
children: React.ReactNode;
}
export const BaseFallback: React.FC<BaseFallbackProps> = ({
children,
...props
}) => {
const theme = useTheme();
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
return (
<Stack
alignItems={"center"}
margin={isSmall ? "inherit" : "auto"}
marginTop={isSmall ? "33%" : "10%"}
width={{
sm: "90%",
md: "70%",
lg: "50%",
xl: "40%",
}}
padding={{ xs: theme.spacing(4), md: theme.spacing(16) }}
bgcolor={theme.palette.primary.main}
border={1}
borderColor={theme.palette.primary.lowContrast}
borderRadius={theme.shape.borderRadius}
sx={{
borderStyle: "dashed",
}}
{...props}
>
<Box
mt={theme.spacing(32)}
mb={theme.spacing(8)}
width={"80%"}
maxWidth={216}
>
<SkeletonCard showHalo={true} />
</Box>
{children}
</Stack>
);
};
export const ErrorFallback = ({
title,
subtitle,
}: {
title: string;
subtitle: string;
}) => {
const theme = useTheme();
return (
<BaseFallback>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
{title}
</Typography>
<Typography>{subtitle}</Typography>
</BaseFallback>
);
};
export const EmptyFallback = ({
title,
bullets,
actionButtonText,
actionLink,
}: {
title: string;
bullets: any;
actionButtonText: string;
actionLink: string;
}) => {
const theme = useTheme();
const navigate = useNavigate();
return (
<BaseFallback>
<Stack gap={theme.spacing(10)} zIndex={1} alignItems="center">
<Typography component="h1" color={theme.palette.primary.contrastText}>
{title}
</Typography>
<Stack
sx={{
flexWrap: "wrap",
gap: theme.spacing(2),
maxWidth: "1100px",
width: "100%",
}}
>
{bullets?.map((bullet: string) => (
<BulletPointCheck
text={bullet}
key={`${bullet}-${Math.random()}`}
/>
))}
</Stack>
<Stack>
<Button
variant="contained"
color="accent"
onClick={() => navigate(actionLink)}
>
{actionButtonText}
</Button>
</Stack>
</Stack>
</BaseFallback>
);
};
export const EmptyMonitorFallback = ({
page,
title,
bullets,
actionButtonText,
actionLink,
}: {
page: string;
title: string;
bullets: any;
actionButtonText: string;
actionLink: string;
}) => {
const theme = useTheme();
const navigate = useNavigate();
return (
<BaseFallback>
<Stack gap={theme.spacing(10)} zIndex={1} alignItems="center">
<Typography component="h1" color={theme.palette.primary.contrastText}>
{title}
</Typography>
<Stack
sx={{
flexWrap: "wrap",
gap: theme.spacing(2),
maxWidth: "1100px",
width: "100%",
}}
>
{bullets?.map((bullet: string, index: number) => (
<BulletPointCheck
text={bullet}
key={`${(page + "Monitors").trim().split(" ")[0]}-${index}`}
/>
))}
</Stack>
<Stack>
<Button
variant="contained"
color="accent"
onClick={() => navigate(actionLink)}
>
{actionButtonText}
</Button>
</Stack>
</Stack>
</BaseFallback>
);
};