import Box from "@mui/material/Box"; import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; import { useTheme } from "@mui/material/styles"; import type { ResponsiveStyleValue } from "@mui/system"; import type { CheckSnapshot } from "@/Types/Check"; import { HeatmapResponseTimeTooltip } from "./HeatmapResponseTimeTooltip"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; interface HistogramResponseTimeProps { checks: CheckSnapshot[]; height?: ResponsiveStyleValue; gap?: ResponsiveStyleValue; showStats?: boolean; statsPosition?: "left" | "right"; } interface ResponseTimeStats { max: number | string; avg: number | string; } const DEFAULT_HEIGHT = 50; const calculateResponseTimeStats = (checks: CheckSnapshot[]): ResponseTimeStats => { if (!Array.isArray(checks) || checks.length === 0) { return { max: "-", avg: "-" }; } const validChecks = checks.filter((check) => check.originalResponseTime != null); if (validChecks.length === 0) { return { max: "-", avg: "-" }; } const responseTimes = validChecks.map((check) => check.originalResponseTime); const max = Math.max(...responseTimes); const avg = Math.round( responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length ); return { max, avg }; }; export const HistogramResponseTime = ({ checks, height = DEFAULT_HEIGHT, gap, showStats = true, statsPosition = "right", }: HistogramResponseTimeProps) => { const theme = useTheme(); const { t } = useTranslation(); const stats = useMemo(() => calculateResponseTimeStats(checks), [checks]); if (!Array.isArray(checks) || checks.length === 0) return null; const data = checks.length !== 25 ? [...checks, ...Array(25 - checks.length).fill({ status: "placeholder" })] : checks; const chartHeight = typeof height === "number" ? `${height}px` : height; const gridGap = gap ?? theme.spacing(0.5); const statsContent = showStats && (typeof stats.max === "number" || typeof stats.avg === "number") && ( {t("common.charts.histogram.avg", { value: stats.avg })} {t("common.charts.histogram.max", { value: stats.max })} ); return ( {data.map((check, index) => { const isPlaceholder = (check as any).status === "placeholder"; const heightPct = `${Math.max(0, Math.min(100, (check as any).responseTime ?? 0))}%`; const barColor = check.status === true ? theme.palette.success.light : theme.palette.error.light; const bar = ( ); return isPlaceholder ? ( {bar} ) : ( {bar} ); })} {statsContent} ); };