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;
|