import { motion } from 'framer-motion'; import React from 'react'; import { useTranslation } from '@/hooks/useI18n'; import { CheckCircle, Clock, User } from 'lucide-react'; import { Flex, Stack } from '@/components/ui/layout'; export interface TimelineEntry { id: string; timestamp: string | Date; title: string; description?: string; actor?: string; action?: string; status?: string; oldValue?: string; newValue?: string; } interface TimelineProps { entries: TimelineEntry[]; className?: string; } const Timeline: React.FC = ({ entries, className = '' }) => { const { t } = useTranslation(); const getActionIcon = (action?: string) => { switch (action?.toLowerCase()) { case 'status_change': return ; case 'comment': return ; case 'update': return ; default: return ; } }; const getActionColor = (action?: string) => { switch (action?.toLowerCase()) { case 'status_change': return 'border-success/20 bg-success/10'; case 'comment': return 'border-primary/20 bg-primary/10'; case 'update': return 'border-warning/20 bg-warning/10'; default: return 'border-muted bg-muted/30'; } }; const formatTimestamp = (timestamp: string | Date) => { const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp; const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffMinutes = Math.floor(diffMs / (1000 * 60)); let relative: string; if (diffMinutes < 1) { relative = 'just now'; } else if (diffMinutes < 60) { relative = `${diffMinutes} minutes ago`; } else if (diffHours < 24) { relative = `${diffHours} hours ago`; } else if (diffDays < 7) { relative = `${diffDays} days ago`; } else { relative = date.toLocaleDateString(); } const absolute = date.toLocaleString(); return { relative, absolute }; }; if (!entries || entries.length === 0) { return (

{t('timeline.noEntries', 'No timeline entries')}

); } // Sort entries by timestamp (most recent first) const sortedEntries = [...entries].sort((a, b) => { const dateA = typeof a.timestamp === 'string' ? new Date(a.timestamp) : a.timestamp; const dateB = typeof b.timestamp === 'string' ? new Date(b.timestamp) : b.timestamp; return dateB.getTime() - dateA.getTime(); }); return (
{/* Timeline line */}
{sortedEntries.map((entry, index) => { const timestamp = formatTimestamp(entry.timestamp); return ( {/* Timeline dot */}
{getActionIcon(entry.action)}
{/* Content */}

{entry.title}

{entry.description && (

{entry.description}

)} {entry.actor && (
{entry.actor}
)} {/* Status change details */} {entry.action === 'status_change' && entry.oldValue && entry.newValue && (
{t('timeline.status')} {entry.oldValue} {entry.newValue}
)} {/* Notes */} {entry.oldValue && entry.action !== 'status_change' && (
{entry.oldValue}
)}
); })}
); }; export default React.memo(Timeline);