diff --git a/Client/src/Components/Charts/Gauge/index.jsx b/Client/src/Components/Charts/Gauge/index.jsx new file mode 100644 index 000000000..0ae872e3f --- /dev/null +++ b/Client/src/Components/Charts/Gauge/index.jsx @@ -0,0 +1,124 @@ +import { RadialBarChart, RadialBar, ResponsiveContainer } from "recharts"; +import PropTypes from "prop-types"; +import { useTheme } from "@emotion/react"; + +const MINIMUM_VALUE = 0; +const MAXIMUM_VALUE = 100; +const DATA = [{ value: MAXIMUM_VALUE }]; +const PROGRESS_THRESHOLD = 50; +const DEFAULT_CONTAINER_HEIGHT = 160; +const TEXT_POSITIONS = { + value: { x: "50%", y: "45%" }, + label: { x: "50%", y: "55%" }, +}; +const COMMON_RADIAL_BAR_PROPS = { + minAngle: 15, + clockWise: true, + dataKey: "value", + cornerRadius: 0, +}; + +const RADIAL_BAR_CHART_PROPS = { + cx: "50%", + cy: "50%", + innerRadius: "45%", + outerRadius: "100%", + startAngle: 90, + endAngle: -270, +}; + +const RADIAL_BAR_OVERLAY_PROPS = { + transform: "rotate(180deg)", + position: "absolute", + top: "0", + left: "0", +}; + +const COMMON_HEADER_PROPS = { + textAnchor: "middle", + dominantBaseline: "middle", +}; + +/** + * A circular gauge component that displays a progress value and text. + * The gauge fills based on the progress value and changes color at a 50% threshold. + * + * @component + * @param {Object} props - Component props + * @param {number} props.progressValue - The value to display in the gauge (0-100) + * @param {string} props.displayText - The text to display below the progress value + * @param {number} [props.containerHeight=160] - Height of the gauge container in pixels + * @param {Object} [props.gaugeHeader] - Custom styles to apply to the progress value text + * @param {Object} [props.gaugeSubheader] - Custom styles to apply to the display text + * + * @returns {JSX.Element} A circular gauge chart with progress value and text + * + * @example + * + */ +const Gauge = ({ + progressValue, + displayText, + containerHeight, + gaugeHeader, + gaugeSubheader, +}) => { + const theme = useTheme(); + const myProgressValue = Math.max(MINIMUM_VALUE, Math.min(progressValue, MAXIMUM_VALUE)); + + return ( + + + PROGRESS_THRESHOLD + ? theme.palette.primary.main + : theme.palette.percentage.uptimePoor + } + background={{ fill: theme.palette.background.fill }} + data={[{ value: myProgressValue }]} + /> + + + {`${myProgressValue}%`} + + + {`${displayText}`} + + + + ); +}; + +Gauge.propTypes = { + progressValue: PropTypes.number.isRequired, + displayText: PropTypes.string.isRequired, + containerHeight: PropTypes.number, + gaugeHeader: PropTypes.object, + gaugeSubheader: PropTypes.object, +}; +export default Gauge; diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index d182f0496..6eca20aa3 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -29,6 +29,18 @@ const darkTheme = createTheme({ body1: { fontSize: 13, color: text.tertiary, fontWeight: 400 }, body2: { fontSize: 12, color: text.tertiary, fontWeight: 400 }, }, + chart: { + header: { + fontWeight: 400, + fill: text.tertiary, + fontSize: 11, + }, + subheader: { + fontWeight: 400, + fill: text.tertiary, + fontSize: 9, + }, + }, palette: { mode: "dark", primary: { main: "#1570ef" }, diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index d2bfafaf4..e6335a062 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -12,6 +12,7 @@ const background = { fill: "#F4F4F4", accent: "#f9fafb", }; + const border = { light: "#eaecf0", dark: "#d0d5dd" }; const fontFamilyDefault = @@ -28,6 +29,18 @@ const lightTheme = createTheme({ body1: { fontSize: 13, color: text.tertiary, fontWeight: 400 }, body2: { fontSize: 12, color: text.tertiary, fontWeight: 400 }, }, + chart: { + header: { + fontWeight: 400, + fill: text.tertiary, + fontSize: 11, + }, + subheader: { + fontWeight: 400, + fill: text.tertiary, + fontSize: 9, + }, + }, palette: { primary: { main: "#1570EF" }, secondary: { main: "#F4F4F4", dark: "#e3e3e3", contrastText: "#475467" },