"use client"; import type { RecapTimelineSegment } from "@/lib/recap/types"; type Props = { rangeStart: string; rangeEnd: string; segments: RecapTimelineSegment[]; locale: string; }; const COLORS: Record = { production: "bg-emerald-500 text-emerald-50", "mold-change": "bg-blue-400 text-blue-950", macrostop: "bg-red-500 text-red-50", microstop: "bg-orange-500 text-orange-50", "slow-cycle": "bg-amber-500 text-amber-950", idle: "bg-zinc-600 text-zinc-100", }; function fmtTime(valueMs: number, locale: string) { return new Date(valueMs).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" }); } function fmtDuration(startMs: number, endMs: number) { const totalMin = Math.max(0, Math.round((endMs - startMs) / 60000)); if (totalMin < 60) return `${totalMin}m`; const h = Math.floor(totalMin / 60); const m = totalMin % 60; return `${h}h ${m}m`; } export default function RecapTimeline({ rangeStart, rangeEnd, segments, locale }: Props) { const startMs = new Date(rangeStart).getTime(); const endMs = new Date(rangeEnd).getTime(); const totalMs = Math.max(1, endMs - startMs); const bars: RecapTimelineSegment[] = []; const dots: Array<{ leftPct: number; segment: RecapTimelineSegment }> = []; for (const segment of segments) { const widthPct = ((segment.endMs - segment.startMs) / totalMs) * 100; const leftPct = ((segment.startMs - startMs) / totalMs) * 100; if (widthPct < 1) { if (segment.type !== "idle" && leftPct > 0.5 && leftPct < 99.5) { dots.push({ leftPct, segment }); } } else { bars.push(segment); } } return (
Timeline 24h
{bars.map((segment) => { const widthPct = ((segment.endMs - segment.startMs) / totalMs) * 100; const title = `${segment.type} · ${fmtTime(segment.startMs, locale)}-${fmtTime(segment.endMs, locale)} · ${fmtDuration(segment.startMs, segment.endMs)}${segment.label ? ` · ${segment.label}` : ""}`; return (
{widthPct >= 6 ? segment.label : ""}
); })}
{dots.map(({ leftPct, segment }) => (
))}
); }