import React, { useState, useEffect, useMemo } from 'react'; import { useParams, Link } from 'react-router-dom'; import { ArrowLeft, Video } from 'lucide-react'; export default function EventTimeline() { const { id } = useParams(); const [events, setEvents] = useState([]); const [loading, setLoading] = useState(true); const API_BASE = '/api'; useEffect(() => { async function fetchData() { try { const query = id ? `?changeover_id=${id}` : ''; const res = await fetch(`${API_BASE}/events${query}`); if (res.ok) { setEvents(await res.json()); } } catch (err) { console.error("Error fetching events", err); } finally { setLoading(false); } } fetchData(); }, [id]); const formatDuration = (seconds) => { if (!seconds) return '0s'; const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); const s = seconds % 60; let res = []; if (h > 0) res.push(`${h}h`); if (m > 0) res.push(`${m}m`); if (s > 0) res.push(`${s}s`); return res.join(' ') || '0s'; }; const getStateBadge = (state) => { const s = state?.toLowerCase() || ''; if (s === 'active') return Active; if (s === 'waste') return Waste; if (s === 'idle') return Idle; if (s === 'load waiting') return Load Wait; return {state}; }; const chronologicalBlocks = useMemo(() => { const blocks = {}; events.forEach(ev => { // Group by exact time (HH:MM:SS) for a waterfall layout const timeKey = ev.start_time.substring(0, 8); if (!blocks[timeKey]) { blocks[timeKey] = { timeKey, CO: [], Mill: [], Conveyor: [] }; } if (ev.camera_zone === 'CO') blocks[timeKey].CO.push(ev); if (ev.camera_zone === 'Mill') blocks[timeKey].Mill.push(ev); if (ev.camera_zone === 'Conveyor') blocks[timeKey].Conveyor.push(ev); }); // Sort chronologically return Object.values(blocks).sort((a, b) => a.timeKey.localeCompare(b.timeKey)); }, [events]); const renderEventCard = (ev, i, arrLength) => (
e.currentTarget.style.background = 'rgba(255, 255, 255, 0.06)'} onMouseLeave={(e) => e.currentTarget.style.background = 'rgba(255, 255, 255, 0.03)'} >
{ev.start_time.substring(0, 8)} - {ev.end_time.substring(0, 8)} {getStateBadge(ev.state)}

{ev.event_description}

Duration: {formatDuration(ev.state_duration_seconds)}
Std Cycle: N/A
Manpower: Nil
); if (loading) { return (

Loading Timeline...

); } return (
Back to Changeover Analytics

Event Timeline: {id}

Synchronized Swimlane Timeline

{/* Sticky Header Grid */}

Time

CO Timeline

Mill Timeline

Conveyor Timeline

{/* Scrollable Timeline Tracks Container */}
{chronologicalBlocks.length === 0 ? (

No events recorded.

) : ( chronologicalBlocks.map((block, index) => (
{/* Time Anchor Left Column */}
{block.timeKey}
{/* Event Columns */}
{block.CO.map((ev, i) => renderEventCard(ev, i, block.CO.length))}
{block.Mill.map((ev, i) => renderEventCard(ev, i, block.Mill.length))}
{block.Conveyor.map((ev, i) => renderEventCard(ev, i, block.Conveyor.length))}
)) )}
); }