'use client'; import { Fragment } from 'react'; import { ChevronDown, ChevronRight } from 'lucide-react'; import type { FinancialStatementPeriod, SurfaceFinancialRow, DetailFinancialRow } from '@/lib/types'; import { cn } from '@/lib/utils'; import type { StatementInspectorSelection, StatementTreeNode, StatementTreeSection } from '@/lib/financials/statement-view-model'; type MatrixRow = SurfaceFinancialRow | DetailFinancialRow; type StatementMatrixProps = { periods: FinancialStatementPeriod[]; sections: StatementTreeSection[]; selectedRowRef: StatementInspectorSelection | null; onToggleRow: (key: string) => void; onSelectRow: (selection: StatementInspectorSelection) => void; renderCellValue: (row: MatrixRow, periodId: string, previousPeriodId: string | null) => string; periodLabelFormatter: (value: string) => string; }; function isSurfaceNode(node: StatementTreeNode): node is Extract { return node.kind === 'surface'; } function rowSelected( node: StatementTreeNode, selectedRowRef: StatementInspectorSelection | null ) { if (!selectedRowRef) { return false; } if (node.kind === 'surface') { return selectedRowRef.kind === 'surface' && selectedRowRef.key === node.row.key; } return selectedRowRef.kind === 'detail' && selectedRowRef.key === node.row.key && selectedRowRef.parentKey === node.parentSurfaceKey; } function surfaceBadges(node: Extract) { const badges: Array<{ label: string; tone: 'default' | 'warning' | 'muted' }> = []; if (node.row.resolutionMethod === 'formula_derived') { badges.push({ label: 'Formula', tone: node.row.confidence === 'low' ? 'warning' : 'default' }); } if (node.row.resolutionMethod === 'not_meaningful') { badges.push({ label: 'N/M', tone: 'muted' }); } if (node.row.confidence === 'low') { badges.push({ label: 'Low confidence', tone: 'warning' }); } const detailCount = node.row.detailCount ?? node.directDetailCount; if (detailCount > 0) { badges.push({ label: `${detailCount} details`, tone: 'default' }); } return badges; } function badgeClass(tone: 'default' | 'warning' | 'muted') { if (tone === 'warning') { return 'border-[#84614f] bg-[rgba(112,76,54,0.22)] text-[#ffd7bf]'; } if (tone === 'muted') { return 'border-[color:var(--line-weak)] bg-[rgba(80,85,92,0.16)] text-[color:var(--terminal-muted)]'; } return 'border-[color:var(--line-weak)] bg-[rgba(88,102,122,0.16)] text-[color:var(--terminal-bright)]'; } function renderNodes(props: StatementMatrixProps & { nodes: StatementTreeNode[] }) { return props.nodes.map((node) => { const isSelected = rowSelected(node, props.selectedRowRef); const labelIndent = node.kind === 'detail' ? node.level * 18 + 18 : node.level * 18; const canToggle = isSurfaceNode(node) && node.expandable; const nextSelection: StatementInspectorSelection = node.kind === 'surface' ? { kind: 'surface', key: node.row.key } : { kind: 'detail', key: node.row.key, parentKey: node.parentSurfaceKey }; return (
{canToggle ? ( ) : ( )}
{props.periods.map((period, index) => ( {props.renderCellValue(node.row, period.id, index > 0 ? props.periods[index - 1]?.id ?? null : null)} ))} {isSurfaceNode(node) && node.expanded ? ( <> Expanded children for {node.row.label} {renderNodes({ ...props, nodes: node.children })} ) : null}
); }); } export function StatementMatrix(props: StatementMatrixProps) { return (
{props.periods.map((period) => ( ))} {props.sections.map((section) => ( {section.label ? ( ) : null} {renderNodes({ ...props, nodes: section.nodes })} ))}
Metric
{props.periodLabelFormatter(period.periodEnd ?? period.filingDate)} {period.filingType} · {period.periodLabel}
{section.label}
); }