import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import type { BusStopUsagePoint } from "~/api/schema"; interface StopUsageChartProps { usage: BusStopUsagePoint[]; } export const StopUsageChart = ({ usage }: StopUsageChartProps) => { const { t } = useTranslation(); // Get current day of week (1=Monday, 7=Sunday) // JS getDay(): 0=Sunday, 1=Monday ... 6=Saturday const currentJsDay = new Date().getDay(); const initialDay = currentJsDay === 0 ? 7 : currentJsDay; const currentHour = new Date().getHours(); const [selectedDay, setSelectedDay] = useState(initialDay); const days = [ { id: 1, label: t("days.monday", "L") }, { id: 2, label: t("days.tuesday", "M") }, { id: 3, label: t("days.wednesday", "X") }, { id: 4, label: t("days.thursday", "J") }, { id: 5, label: t("days.friday", "V") }, { id: 6, label: t("days.saturday", "S") }, { id: 7, label: t("days.sunday", "D") }, ]; const filteredData = useMemo(() => { const data = usage.filter((u) => u.d === selectedDay); // Ensure all 24 hours are represented const fullDay = Array.from({ length: 24 }, (_, h) => { const match = data.find((u) => u.h === h); return { h, t: match?.t ?? 0 }; }); return fullDay; }, [usage, selectedDay]); const maxUsage = useMemo(() => { const max = Math.max(...filteredData.map((d) => d.t)); return max === 0 ? 1 : max; }, [filteredData]); // Use a linear scale const getScaledHeight = (value: number) => { if (value <= 0) return 0; return (value / maxUsage) * 100; }; if (!usage || usage.length === 0) return null; return (

{t("stop.usage_title", "Ocupación por horas")}

{days.map((day) => ( ))}
{/* Horizontal grid lines */}
{filteredData.map((data) => { const height = getScaledHeight(data.t); const isServiceHour = data.h >= 7 && data.h < 23; const isCurrentHour = selectedDay === initialDay && data.h === currentHour; let barBg = "bg-slate-300 dark:bg-slate-700 group-hover:bg-slate-400"; if (isCurrentHour) { barBg = "bg-red-500 group-hover:bg-red-600 shadow-[0_0_10px_rgba(239,68,68,0.4)]"; } else if (isServiceHour) { barBg = "bg-primary/60 group-hover:bg-primary shadow-[0_0_10px_rgba(var(--primary-rgb),0.2)]"; } return (
{data.t > 0 && (
{data.t}
)}
{data.h % 4 === 0 && ( {data.h}h )}
); })}
{/* Spacer for hour labels */}

{t( "stop.usage_disclaimer", "Datos históricos aproximados de ocupación." )}

); };