import React, { useEffect, useRef } from "react" import { Download } from "lucide-react" import type { MetricEntry, ActivityLogEntry } from "@/lib/api" interface UserEvent { timestamp: string message: string } interface ActivityLogProps { metrics: MetricEntry[] activityLog: ActivityLogEntry[] currentStep: string revisionCount: number score: number isTyping?: boolean userEvents?: UserEvent[] } function formatTime(timestamp: string): string { try { const date = new Date(timestamp) return date.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }) } catch { return '' } } function formatValue(value: string | number): string { if (typeof value === "number") { if (Math.abs(value) >= 1e9) return `$${(value / 1e9).toFixed(1)}B` if (Math.abs(value) >= 1e6) return `$${(value / 1e6).toFixed(1)}M` if (Math.abs(value) < 100) return value.toFixed(2) return value.toLocaleString() } return String(value) } function getCurrentTime(): string { return new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }) } export function ActivityLog({ metrics, activityLog, currentStep, revisionCount, score, isTyping = false, userEvents = [], }: ActivityLogProps) { const logRef = useRef(null) // Auto-scroll to bottom when new entries arrive useEffect(() => { if (logRef.current) { logRef.current.scrollTop = logRef.current.scrollHeight } }, [metrics, activityLog, isTyping, userEvents]) // Combine and sort all log entries const allEntries = React.useMemo(() => { const entries: Array<{ time: string; text: string; type: 'metric' | 'activity' | 'user' }> = [] // Add user events first for (const e of userEvents) { entries.push({ time: formatTime(e.timestamp), text: `[user] ${e.message}`, type: 'user' }) } // Add metrics for (const m of metrics) { entries.push({ time: formatTime(m.timestamp), text: `[${m.source}] ${m.metric}: ${formatValue(m.value)}`, type: 'metric' }) } // Add activity log for (const a of activityLog) { entries.push({ time: formatTime(a.timestamp), text: `[${a.step}] ${a.message}`, type: 'activity' }) } // Sort by timestamp return entries.sort((a, b) => a.time.localeCompare(b.time)) }, [metrics, activityLog, userEvents]) // Download log as text file const handleDownload = () => { const logContent = allEntries.map(e => `${e.time} ${e.text}`).join('\n') const blob = new Blob([logContent], { type: 'text/plain' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `analysis-log-${new Date().toISOString().split('T')[0]}.txt` document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) } return (
{/* Header */}
Activity Log
{/* Log content */}
{allEntries.length === 0 && !isTyping ? (
Waiting for input...
) : ( <> {allEntries.map((entry, i) => (
{entry.time} {' '} {entry.text}
))} {/* Live typing indicator */} {isTyping && (
{getCurrentTime()} {' '} [user] Typing...
)} )}
{/* Footer */}
Step: {currentStep} {revisionCount > 0 && Rev #{revisionCount}}
) } export default ActivityLog