import Link from 'next/link'; import { Badge, ClaimBadge } from '@/components/ui/badge'; import { SourceBadge, provenanceTitle, type ProvenanceInfo } from '@/components/ui/source-badge'; import { Pager } from '@/components/ui/pager'; import { EPI_METRIC_LABEL } from '@/lib/queries/epidemiology'; import type { ExplorerObsRow } from '@/lib/queries/explorer'; import { TABLE_PAGE_SIZE } from '@/lib/explorer-params'; import { fmtInt, fmtValue, humanize, unitLabel } from '@/lib/format'; export function obsProvenance(r: ExplorerObsRow): ProvenanceInfo { return { sourceSlug: r.source_slug, sourceName: r.source_name, dataset: r.dataset, datasetVersion: r.dataset_version, retrievedAt: r.retrieved_at, sourceUrl: r.source_url, license: r.source_license, layer: 'normalized', evidenceType: 'observed_data', }; } /** * Every observation behind the charts, 50 per page, with the unit, CI, estimate type, standard * population, site definition and a per-row provenance popover (datasets differ between rows). */ export function ObservationsTable({ rows, page, hrefFor }: { rows: ExplorerObsRow[]; page: number; hrefFor: (page: number) => string }) { const total = rows.length; const start = (page - 1) * TABLE_PAGE_SIZE; const shown = rows.slice(start, start + TABLE_PAGE_SIZE); const units = [...new Set(rows.map((r) => r.unit))]; const observedOnly = rows.every((r) => r.estimate_type === 'observed'); // One provenance popover per distinct (source, dataset) in the caption; rows carry compact badges whose // title repeats dataset · version · retrieved (dense tables: the popover markup is not repeated 50 times). const captionProv = new Map(); for (const r of rows) { const k = `${r.source_slug}|${r.dataset ?? ''}`; if (!captionProv.has(k)) captionProv.set(k, obsProvenance(r)); } return (
{/* div, not p: popovers contain a
. */}
{[...captionProv.values()].map((p) => ( ))} {fmtInt(total)} observation{total === 1 ? '' : 's'} · values exactly as published by the source, units harmonized ({units.map(unitLabel).join(', ')}) · hover a row's source badge for its dataset, version and retrieval date {observedOnly ? '' : ' · rows labelled estimated/projected are model outputs of the source'}
{shown.map((r) => ( ))}
Year Cancer Geography Sex Age Metric Value Unit 95% CI Type Standard population Site definition Source
{r.year_end && r.year_end !== r.year ? `${r.year}–${r.year_end}` : r.year} {r.cancer_name} {r.geography_name} {r.sex === 'all' ? 'Both' : humanize(r.sex)} {r.age_group === 'all' ? 'All ages' : r.age_group} {EPI_METRIC_LABEL[r.metric] ?? humanize(r.metric)} {fmtValue(r.value, r.unit)} {unitLabel(r.unit)} {r.lower_ci != null && r.upper_ci != null ? `${fmtValue(r.lower_ci, r.unit)}–${fmtValue(r.upper_ci, r.unit)}` : '—'} {r.estimate_type} {r.standard_population ?? '—'} {r.site_definition ?? '—'}
); }