Implement fiscal-style research MVP flows
Some checks failed
PR Checks / typecheck-and-build (push) Has been cancelled

This commit is contained in:
2026-03-07 09:51:18 -05:00
parent f69e5b671b
commit 52136271d3
26 changed files with 2719 additions and 243 deletions

View File

@@ -178,6 +178,50 @@ function mergeSurfaceRows<T extends { key: string; values: Record<string, number
return [...rowMap.values()];
}
function mergeOverviewMetrics(
base: CompanyFinancialStatementsResponse['overviewMetrics'],
next: CompanyFinancialStatementsResponse['overviewMetrics']
): CompanyFinancialStatementsResponse['overviewMetrics'] {
const mergedSeriesMap = new Map<string, CompanyFinancialStatementsResponse['overviewMetrics']['series'][number]>();
for (const source of [base.series, next.series]) {
for (const point of source) {
const existing = mergedSeriesMap.get(point.periodId);
if (!existing) {
mergedSeriesMap.set(point.periodId, { ...point });
continue;
}
existing.filingDate = existing.filingDate || point.filingDate;
existing.periodEnd = existing.periodEnd ?? point.periodEnd;
existing.label = existing.label || point.label;
existing.revenue = existing.revenue ?? point.revenue;
existing.netIncome = existing.netIncome ?? point.netIncome;
existing.totalAssets = existing.totalAssets ?? point.totalAssets;
existing.cash = existing.cash ?? point.cash;
existing.debt = existing.debt ?? point.debt;
}
}
const series = [...mergedSeriesMap.values()].sort((left, right) => {
return Date.parse(left.periodEnd ?? left.filingDate) - Date.parse(right.periodEnd ?? right.filingDate);
});
const latest = series[series.length - 1] ?? null;
return {
referencePeriodId: next.referencePeriodId ?? base.referencePeriodId ?? latest?.periodId ?? null,
referenceDate: next.referenceDate ?? base.referenceDate ?? latest?.filingDate ?? null,
latest: {
revenue: next.latest.revenue ?? base.latest.revenue ?? latest?.revenue ?? null,
netIncome: next.latest.netIncome ?? base.latest.netIncome ?? latest?.netIncome ?? null,
totalAssets: next.latest.totalAssets ?? base.latest.totalAssets ?? latest?.totalAssets ?? null,
cash: next.latest.cash ?? base.latest.cash ?? latest?.cash ?? null,
debt: next.latest.debt ?? base.latest.debt ?? latest?.debt ?? null
},
series
};
}
function mergeFinancialPages(
base: CompanyFinancialStatementsResponse | null,
next: CompanyFinancialStatementsResponse
@@ -317,6 +361,7 @@ function mergeFinancialPages(
...next.dataSourceStatus,
queuedSync: base.dataSourceStatus.queuedSync || next.dataSourceStatus.queuedSync
},
overviewMetrics: mergeOverviewMetrics(base.overviewMetrics, next.overviewMetrics),
dimensionBreakdown
};
}
@@ -342,6 +387,33 @@ function buildOverviewSeries(
incomeData: CompanyFinancialStatementsResponse | null,
balanceData: CompanyFinancialStatementsResponse | null
): OverviewPoint[] {
const overviewSeriesMap = new Map<string, OverviewPoint>();
for (const source of [incomeData?.overviewMetrics.series ?? [], balanceData?.overviewMetrics.series ?? []]) {
for (const point of source) {
const existing = overviewSeriesMap.get(point.periodId);
if (!existing) {
overviewSeriesMap.set(point.periodId, { ...point });
continue;
}
existing.filingDate = existing.filingDate || point.filingDate;
existing.periodEnd = existing.periodEnd ?? point.periodEnd;
existing.label = existing.label || point.label;
existing.revenue = existing.revenue ?? point.revenue;
existing.netIncome = existing.netIncome ?? point.netIncome;
existing.totalAssets = existing.totalAssets ?? point.totalAssets;
existing.cash = existing.cash ?? point.cash;
existing.debt = existing.debt ?? point.debt;
}
}
if (overviewSeriesMap.size > 0) {
return [...overviewSeriesMap.values()].sort((left, right) => {
return Date.parse(left.periodEnd ?? left.filingDate) - Date.parse(right.periodEnd ?? right.filingDate);
});
}
const periodMap = new Map<string, { filingDate: string; periodEnd: string | null }>();
for (const source of [incomeData, balanceData]) {
@@ -609,27 +681,36 @@ function FinancialsPageContent() {
const latestStandardizedIncome = overviewIncome?.surfaces.standardized.rows ?? [];
const latestStandardizedBalance = overviewBalance?.surfaces.standardized.rows ?? [];
const latestRevenue = latestOverview?.revenue
const latestRevenue = overviewIncome?.overviewMetrics.latest.revenue
?? latestOverview?.revenue
?? findStandardizedRow(latestStandardizedIncome, 'revenue')?.values[periods[periods.length - 1]?.id ?? '']
?? latestTaxonomyMetrics?.revenue
?? null;
const latestNetIncome = latestOverview?.netIncome
const latestNetIncome = overviewIncome?.overviewMetrics.latest.netIncome
?? latestOverview?.netIncome
?? findStandardizedRow(latestStandardizedIncome, 'net-income')?.values[periods[periods.length - 1]?.id ?? '']
?? latestTaxonomyMetrics?.netIncome
?? null;
const latestTotalAssets = latestOverview?.totalAssets
const latestTotalAssets = overviewBalance?.overviewMetrics.latest.totalAssets
?? latestOverview?.totalAssets
?? findStandardizedRow(latestStandardizedBalance, 'total-assets')?.values[periods[periods.length - 1]?.id ?? '']
?? latestTaxonomyMetrics?.totalAssets
?? null;
const latestCash = latestOverview?.cash
const latestCash = overviewBalance?.overviewMetrics.latest.cash
?? latestOverview?.cash
?? findStandardizedRow(latestStandardizedBalance, 'cash-and-equivalents')?.values[periods[periods.length - 1]?.id ?? '']
?? latestTaxonomyMetrics?.cash
?? null;
const latestDebt = latestOverview?.debt
const latestDebt = overviewBalance?.overviewMetrics.latest.debt
?? latestOverview?.debt
?? findStandardizedRow(latestStandardizedBalance, 'total-debt')?.values[periods[periods.length - 1]?.id ?? '']
?? latestTaxonomyMetrics?.debt
?? null;
const latestReferenceDate = latestOverview?.filingDate ?? periods[periods.length - 1]?.filingDate ?? null;
const latestReferenceDate = overviewIncome?.overviewMetrics.referenceDate
?? overviewBalance?.overviewMetrics.referenceDate
?? latestOverview?.filingDate
?? periods[periods.length - 1]?.filingDate
?? null;
const selectedRow = useMemo(() => {
if (!selectedRowKey) {