'use client' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Trophy, AlertTriangle, Lightbulb, Brain, Flame, Wrench, Clock, MessageSquare, FolderOpen, LayoutList, DollarSign, Terminal, Zap, Search, Ban, Calendar, } from 'lucide-react' import { formatCost, formatDuration, formatNumber, formatTokens } from '@/lib/format' import type { ReportContent } from '@/lib/report' import type { CoachInsight, InsightSeverity, InsightCategory } from '@/lib/coach' // ─── Score Ring ────────────────────────────────────────────────────── function ScoreRing({ score, size = 140 }: { score: number; size?: number }) { const radius = (size - 14) / 2 const circumference = 2 * Math.PI * radius const offset = circumference - (score / 100) * circumference const getColor = (s: number) => { if (s >= 85) return 'var(--chart-2)' if (s >= 70) return 'var(--chart-1)' if (s >= 55) return 'var(--chart-3)' return 'var(--chart-5)' } return ( {score} / 100 ) } // ─── Insight Card ──────────────────────────────────────────────────── const SEVERITY_BORDER: Record = { achievement: 'border-l-chart-2', warning: 'border-l-chart-5', tip: 'border-l-chart-1', } const SEVERITY_ICON: Record = { achievement: Trophy, warning: AlertTriangle, tip: Lightbulb, } function InsightCard({ insight }: { insight: CoachInsight }) { const Icon = SEVERITY_ICON[insight.severity] return (
{insight.title}

{insight.description}

{insight.recommendation && (
{insight.recommendation}
)}
{insight.metric && ( {insight.metric} )}
) } // ─── Main Report View ──────────────────────────────────────────────── export function ReportView({ content }: { content: ReportContent }) { const g = content.atAGlance return (
{/* At a Glance */} At a Glance {g.dateRange.from} to {g.dateRange.to}
Fitness: {g.scoreLabel}
{g.currentStreak > 0 ? `${g.currentStreak}d streak` : 'No active streak'} {g.longestStreak > 0 && (best: {g.longestStreak}d)}
Sessions
{formatNumber(g.totalSessions)}
Projects
{formatNumber(g.totalProjects)}
Messages
{formatNumber(g.totalMessages)}
Total Time
{formatDuration(g.totalDurationMinutes)}
Tool Calls
{formatNumber(g.totalToolCalls)}
Total Cost
{formatCost(g.totalCostUSD)}
API Errors
{formatNumber(g.totalApiErrors)}
Interruptions
{formatNumber(g.totalUserInterruptions)}
{/* Project Areas */} {content.projectAreas.length > 0 && (
What You Work On Top projects by session count
Project Sessions Messages Duration Top Tools {content.projectAreas.map(p => ( {p.name} {p.sessions} {formatNumber(p.totalMessages)} {formatDuration(p.totalDurationMinutes)} {p.topTools.map(([name, count]) => `${name} (${count})`).join(', ')} ))}
)} {/* Interaction Style */}
How You Use Your Agent Interaction patterns and coding style
{content.interactionStyle.mbtiType}
{content.interactionStyle.mbtiDescription}
Avg Messages/Session
{Math.round(content.interactionStyle.avgMessagesPerSession)}
Avg Duration
{formatDuration(content.interactionStyle.avgDurationMinutes)}
Read/Edit Ratio
{content.interactionStyle.readEditRatio.toFixed(1)}x
Bash Usage
{Math.round(content.interactionStyle.bashRatio * 100)}%
Subagent Calls
{formatNumber(content.interactionStyle.agentCallsTotal)}
Peak Hour
{content.interactionStyle.peakHour}:00
Most Active Day
{content.interactionStyle.mostActiveDay}
Avg Cost/Session
{formatCost(content.interactionStyle.avgCostPerSession)}
{/* What Works */} {content.whatWorks.length > 0 && (
What's Working Patterns and habits that are paying off
{content.whatWorks.map(i => )}
)} {/* Friction Analysis */} {content.frictionAnalysis.length > 0 && (
Where Things Go Wrong Friction points that slow you down
{content.frictionAnalysis.map(i => )}
)} {/* Suggestions */}
Suggestions Actionable ways to improve your workflow
{/* CLAUDE.md rules */} {content.suggestions.claudeMdRules.length > 0 && (

Add to CLAUDE.md

{content.suggestions.claudeMdRules.map((rule, i) => (
{rule}
))}
)} {/* Coach tips */} {content.suggestions.coachTips.length > 0 && (

Workflow Tips

{content.suggestions.coachTips.map(i => )}
)} {/* Command tips */} {content.suggestions.commandTips.length > 0 && (

Commands to Discover

{content.suggestions.commandTips.map(i => (
{i.title}

{i.description}

{i.recommendation && (
{i.recommendation}
)}
))}
)}
) }