Files
Checkmate/Client/src/Components/StatBox/index.jsx
T

133 lines
3.3 KiB
React
Raw Normal View History

2025-02-05 14:59:08 -08:00
import { Stack, Typography } from "@mui/material";
import Image from "../Image";
2024-12-18 13:44:48 -08:00
import { useTheme } from "@mui/material/styles";
2024-12-18 13:46:51 -08:00
import PropTypes from "prop-types";
2025-01-28 11:05:06 -08:00
import useUtils from "../../Pages/Uptime/Monitors/Hooks/useUtils";
2024-12-18 13:44:48 -08:00
2024-12-18 13:46:51 -08:00
/**
* StatBox Component
*
* A reusable component that displays a statistic with a heading and subheading
* in a styled box with a gradient background.
*
* @component
* @param {Object} props - The component props
* @param {string} props.heading - The primary heading/title of the statistic
* @param {string|React.ReactNode} props.subHeading - The value or description of the statistic
2025-01-12 12:28:13 -05:00
* @param {boolean} [props.gradient=false] - Determines if the box should have a gradient background
* @param {string} [props.status] - The status of the statistic
2024-12-18 13:46:51 -08:00
* @param {Object} [props.sx] - Additional custom styling to be applied to the box
*
* @example
* return (
* <StatBox
* heading="Total Users"
* subHeading="1,234"
* sx={{ width: 300 }}
* />
* )
*
* @returns {React.ReactElement} A styled box containing the statistic
*/
2025-02-05 14:59:08 -08:00
const StatBox = ({
img,
alt,
heading,
subHeading,
gradient = false,
status = "",
sx,
}) => {
2024-12-18 13:44:48 -08:00
const theme = useTheme();
2025-01-12 12:28:13 -05:00
const { statusToTheme } = useUtils();
const themeColor = statusToTheme[status];
const statusBoxStyles = gradient
? {
background: `linear-gradient(to bottom right, ${theme.palette[themeColor].main} 30%, ${theme.palette[themeColor].lowContrast} 70%)`,
borderColor: theme.palette[themeColor].lowContrast,
}
: {
background: `linear-gradient(340deg, ${theme.palette.tertiary.main} 20%, ${theme.palette.primary.main} 45%)`,
borderColor: theme.palette.primary.lowContrast,
};
const headingStyles = gradient
? {
color: theme.palette[themeColor].contrastText,
}
: {
color: theme.palette.primary.contrastTextSecondary,
};
const spanFixedStyles = { marginLeft: theme.spacing(2), fontSize: 15 };
const detailTextStyles = gradient
? {
color: theme.palette[themeColor].contrastText,
"& span": {
color: theme.palette[themeColor].contrastText,
...spanFixedStyles,
},
}
: {
color: theme.palette.primary.contrastText,
"& span": {
color: theme.palette.primary.contrastTextTertiary,
...spanFixedStyles,
},
};
2024-12-18 13:44:48 -08:00
return (
2025-02-05 14:59:08 -08:00
<Stack
direction="row"
2024-12-18 13:44:48 -08:00
sx={{
padding: `${theme.spacing(4)} ${theme.spacing(8)}`,
2025-01-09 13:50:50 -05:00
/* TODO why are we using width and min width here? */
2024-12-18 13:44:48 -08:00
minWidth: 200,
width: 225,
border: 1,
borderStyle: "solid",
borderRadius: 4,
2025-01-12 12:28:13 -05:00
...statusBoxStyles,
2024-12-18 13:44:48 -08:00
"& h2": {
2025-01-12 12:28:13 -05:00
/* TODO font size should come from theme */
2024-12-18 13:44:48 -08:00
fontSize: 13,
fontWeight: 500,
textTransform: "uppercase",
2025-01-12 12:28:13 -05:00
...headingStyles,
2024-12-18 13:44:48 -08:00
},
"& p": {
fontSize: 18,
marginTop: theme.spacing(2),
2025-01-12 12:28:13 -05:00
...detailTextStyles,
2024-12-18 13:44:48 -08:00
},
...sx,
}}
>
2025-02-05 14:59:08 -08:00
{img && (
<Image
src={img}
height={"30px"}
width={"30px"}
alt={alt}
sx={{ marginRight: theme.spacing(8) }}
/>
)}
<Stack>
<Typography component="h2">{heading}</Typography>
<Typography>{subHeading}</Typography>
</Stack>
</Stack>
2024-12-18 13:44:48 -08:00
);
};
2024-12-18 13:46:51 -08:00
StatBox.propTypes = {
heading: PropTypes.string.isRequired,
subHeading: PropTypes.node.isRequired,
2025-01-12 12:28:13 -05:00
gradient: PropTypes.bool,
status: PropTypes.string,
2024-12-18 13:46:51 -08:00
sx: PropTypes.object,
};
2024-12-18 13:44:48 -08:00
export default StatBox;