Files
Checkmate/client/src/Components/design-elements/Fallback.tsx
T

176 lines
3.6 KiB
TypeScript
Raw Normal View History

2026-01-23 19:58:37 +00:00
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
2026-02-20 18:13:39 +00:00
import { BulletPointCheck, SkeletonCard } from "@/Components/design-elements";
import { Button } from "@/Components/inputs";
2026-02-28 22:03:30 +00:00
import { SPACING, LAYOUT } from "@/Utils/Theme/constants";
2026-01-23 19:58:37 +00:00
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 = ({ children, ...props }: BaseFallbackProps) => {
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%",
}}
2026-02-28 22:03:30 +00:00
padding={{ xs: theme.spacing(LAYOUT.MD), md: theme.spacing(LAYOUT.XXL) }}
2026-01-23 19:58:37 +00:00
bgcolor={theme.palette.background.paper}
border={1}
borderColor={theme.palette.divider}
borderRadius={theme.shape.borderRadius}
sx={{
borderStyle: "dashed",
}}
{...props}
>
<SkeletonCard showHalo={true} />
{children}
</Stack>
);
};
export const ErrorFallback = ({
title,
subtitle,
}: {
title: string;
subtitle: string;
}) => {
const theme = useTheme();
return (
<BaseFallback>
<Typography
variant="h1"
2026-02-28 22:03:30 +00:00
marginY={theme.spacing(LAYOUT.XS)}
2026-01-23 19:58:37 +00:00
color={theme.palette.text.secondary}
>
{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
2026-02-28 22:03:30 +00:00
gap={theme.spacing(LAYOUT.MD)}
2026-01-23 19:58:37 +00:00
zIndex={1}
alignItems="center"
>
2026-02-20 18:10:43 +00:00
<Typography component="h1">{title}</Typography>
2026-01-23 19:58:37 +00:00
<Stack
sx={{
flexWrap: "wrap",
2026-02-28 22:03:30 +00:00
gap: theme.spacing(SPACING.MD),
2026-01-23 19:58:37 +00:00
maxWidth: "1100px",
width: "100%",
}}
>
{Array.isArray(bullets) &&
bullets?.map((bullet: string) => (
<BulletPointCheck
text={bullet}
key={`${bullet}-${Math.random()}`}
/>
))}
</Stack>
<Stack>
<Button
variant="contained"
color="primary"
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
2026-02-28 22:03:30 +00:00
gap={theme.spacing(LAYOUT.MD)}
2026-01-23 19:58:37 +00:00
zIndex={1}
alignItems="center"
>
<Typography
component="h1"
color={theme.palette.primary.contrastText}
>
{title}
</Typography>
<Stack
sx={{
flexWrap: "wrap",
2026-02-28 22:03:30 +00:00
gap: theme.spacing(SPACING.MD),
2026-01-23 19:58:37 +00:00
maxWidth: "1100px",
width: "100%",
}}
>
{Array.isArray(bullets) &&
bullets?.map((bullet: string, index: number) => (
<BulletPointCheck
text={bullet}
key={`${(page + "Monitors").trim().split(" ")[0]}-${index}`}
/>
))}
</Stack>
2026-01-23 12:33:40 -08:00
<Stack>
<Button
variant="contained"
color="primary"
onClick={() => navigate(actionLink)}
>
{actionButtonText}
</Button>
</Stack>
2026-01-23 19:58:37 +00:00
</Stack>
</BaseFallback>
);
};