import { useEffect, useState } from 'react'; import { api } from '@renderer/api'; import { cn } from '@renderer/lib/utils'; import { formatRelativeTime } from '@renderer/utils/formatters'; import { getBasename } from '@shared/utils/platformPath'; import { formatTokensCompact } from '@shared/utils/tokenFormatting'; import { AlertCircle, BarChart3, ChevronDown, ChevronRight, FileCode, Info, Loader2, } from 'lucide-react'; import type { FileLineStats, MemberFullStats } from '@shared/types'; interface MemberStatsTabProps { teamName: string; memberName: string; prefetchedStats?: MemberFullStats | null; prefetchedLoading?: boolean; prefetchedError?: string | null; onFileClick?: (filePath: string) => void; onShowAllFiles?: () => void; } export const MemberStatsTab = ({ teamName, memberName, prefetchedStats, prefetchedLoading, prefetchedError, onFileClick, onShowAllFiles, }: MemberStatsTabProps): React.JSX.Element => { const usePrefetched = prefetchedStats !== undefined; const [localStats, setLocalStats] = useState(null); const [localLoading, setLocalLoading] = useState(!usePrefetched); const [localError, setLocalError] = useState(null); useEffect(() => { if (usePrefetched) return; let cancelled = false; setLocalLoading(true); setLocalError(null); void (async () => { try { const result = await api.teams.getMemberStats(teamName, memberName); if (!cancelled) setLocalStats(result); } catch (e) { if (!cancelled) setLocalError(e instanceof Error ? e.message : 'Unknown error'); } finally { if (!cancelled) setLocalLoading(false); } })(); return () => { cancelled = true; }; }, [teamName, memberName, usePrefetched]); const stats = usePrefetched ? (prefetchedStats ?? null) : localStats; const loading = usePrefetched ? (prefetchedLoading ?? false) : localLoading; const error = usePrefetched ? (prefetchedError ?? null) : localError; if (loading) { return (
Computing stats...
); } if (error) { return (
{error}
); } if (!stats) { return (
No stats available
); } const totalTokens = stats.inputTokens + stats.outputTokens; const totalToolCalls = Object.values(stats.toolUsage).reduce((sum, c) => sum + c, 0); return (
); }; const StatCard = ({ label, value, sub, info, }: { label: string; value: string | number; sub?: string; info?: string; }): React.JSX.Element => (

{value}

{label}

{info && ( {info} )}
{sub &&

{sub}

}
); const SummaryCards = ({ stats, totalTokens, totalToolCalls, }: { stats: MemberFullStats; totalTokens: number; totalToolCalls: number; }): React.JSX.Element => (
0 ? `-${stats.linesRemoved}` : undefined} info="Approximate. Accurate for Edit and Write tools. Bash file writes are estimated from command patterns (heredoc, echo, sed) and may be underreported." />
); const ToolUsageBars = ({ toolUsage, }: { toolUsage: Record; }): React.JSX.Element | null => { const entries = Object.entries(toolUsage).sort(([, a], [, b]) => b - a); if (entries.length === 0) return null; const maxCount = entries[0][1]; return (

Tool Usage

{entries.map(([name, count]) => (
{name}
{count}
))}
); }; const TRAILING_PUNCT = ';.,'; function isInvalidPath(path: string): boolean { let trimmed = path.trim(); let end = trimmed.length; while (end > 0 && TRAILING_PUNCT.includes(trimmed[end - 1])) { end--; } trimmed = trimmed.slice(0, end); return !trimmed || trimmed === 'null' || trimmed === 'undefined' || trimmed === 'None'; } const FilesTouchedSection = ({ files, fileStats, onFileClick, onShowAll, }: { files: string[]; fileStats?: Record; onFileClick?: (filePath: string) => void; onShowAll?: () => void; }): React.JSX.Element | null => { const [expanded, setExpanded] = useState(false); const validFiles = files.filter((f) => !isInvalidPath(f)); if (validFiles.length === 0) return null; const visibleFiles = expanded ? validFiles : validFiles.slice(0, 5); const hiddenCount = validFiles.length - 5; const isClickable = !!onFileClick; return (

Files Touched ({validFiles.length})

{onShowAll && ( )}
{visibleFiles.map((filePath) => { const basename = getBasename(filePath) || filePath; const fStats = fileStats?.[filePath]; return ( ); })}
{hiddenCount > 0 && ( )}
); }; const StatsFooter = ({ stats }: { stats: MemberFullStats }): React.JSX.Element => { const computedAgo = formatRelativeTime(stats.computedAt); return (
{stats.sessionCount} session{stats.sessionCount !== 1 ? 's' : ''} ยท computed {computedAgo}
); };