'use client'; import React, { useState, useEffect, useMemo } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Calendar, Clock, Users, ChevronDown, ChevronRight, Activity, AlertCircle, CheckCircle } from 'lucide-react'; import { TimelineEvent, TimelineView as TimelineViewType } from '@/lib/types/analytics'; import { cn } from '@/lib/utils'; interface TimelineViewProps { events: TimelineEvent[]; timeRange: 'hour' | 'day' | 'week' | 'month'; onTimeRangeChange: (range: 'hour' | 'day' | 'week' | 'month') => void; loading?: boolean; className?: string; } export function TimelineView({ events, timeRange, onTimeRangeChange, loading = false, className }: TimelineViewProps) { const [expandedSections, setExpandedSections] = useState>(new Set()); const [selectedEvent, setSelectedEvent] = useState(null); // Group events by time period based on timeRange const groupedEvents = useMemo(() => { const groups = new Map(); events.forEach(event => { const eventDate = new Date(event.timestamp); let groupKey: string; switch (timeRange) { case 'hour': groupKey = eventDate.toISOString().substring(0, 13); // YYYY-MM-DDTHH break; case 'day': groupKey = eventDate.toISOString().substring(0, 10); // YYYY-MM-DD break; case 'week': const weekStart = new Date(eventDate); weekStart.setDate(eventDate.getDate() - eventDate.getDay()); groupKey = `Week of ${weekStart.toISOString().substring(0, 10)}`; break; case 'month': groupKey = eventDate.toISOString().substring(0, 7); // YYYY-MM break; default: groupKey = eventDate.toISOString().substring(0, 10); } if (!groups.has(groupKey)) { groups.set(groupKey, []); } groups.get(groupKey)!.push(event); }); // Sort events within each group by timestamp groups.forEach(group => { group.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); }); return groups; }, [events, timeRange]); // Calculate summary statistics const summary = useMemo(() => { const humanActivities = events.filter(e => e.isHumanActivity).length; const systemActivities = events.filter(e => !e.isHumanActivity).length; const totalHours = events.reduce((sum, e) => sum + (e.duration || 0), 0); const averageScore = events.length > 0 ? events.reduce((sum, e) => sum + (e.score || 0), 0) / events.length : 0; return { totalEvents: events.length, humanActivities, systemActivities, totalHours, averageScore, }; }, [events]); const toggleSection = (sectionKey: string) => { const newExpanded = new Set(expandedSections); if (newExpanded.has(sectionKey)) { newExpanded.delete(sectionKey); } else { newExpanded.add(sectionKey); } setExpandedSections(newExpanded); }; const getEventIcon = (event: TimelineEvent) => { switch (event.type) { case 'key_moment': return ; case 'milestone': return ; case 'time_entry': default: if (event.isHumanActivity) { return ; } else { return ; } } }; const getImportanceColor = (importance: string) => { switch (importance) { case 'critical': return 'bg-red-100 text-red-800 border-red-200'; case 'high': return 'bg-orange-100 text-orange-800 border-orange-200'; case 'medium': return 'bg-yellow-100 text-yellow-800 border-yellow-200'; case 'low': default: return 'bg-gray-100 text-gray-800 border-gray-200'; } }; const formatGroupTitle = (groupKey: string) => { switch (timeRange) { case 'hour': return new Date(groupKey + ':00:00').toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', hour12: true, }); case 'day': return new Date(groupKey).toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', }); case 'week': return groupKey; case 'month': return new Date(groupKey + '-01').toLocaleDateString('en-US', { month: 'long', year: 'numeric', }); default: return groupKey; } }; if (loading) { return ( Timeline View
); } return (
Timeline View
{/* Summary Statistics */}
{summary.totalEvents}
Total Events
{summary.humanActivities}
Human Activities
{summary.systemActivities}
System Activities
{Number(summary.totalHours).toFixed(1)}
Total Hours
{(summary.averageScore * 100).toFixed(0)}%
Avg Score
{groupedEvents.size === 0 ? (

No events found for the selected time range

) : ( Array.from(groupedEvents.entries()) .sort(([a], [b]) => b.localeCompare(a)) // Sort by date descending .map(([groupKey, groupEvents]) => ( toggleSection(groupKey)} > {groupEvents.map((event) => (
setSelectedEvent(event)} >
{getEventIcon(event)}

{event.title}

{event.importance}
{event.description && (

{event.description}

)}
{new Date(event.timestamp).toLocaleTimeString()} {event.duration && ( {event.duration}h )} {event.score && (
{(event.score * 100).toFixed(0)}% )}
))} )) )} ); }