import type { Metadata } from 'next'; import Link from 'next/link'; import { PageHeader, Section, Note } from '@/components/ui/section'; import { Badge, ClaimBadge, StatusBadge } from '@/components/ui/badge'; import { EmptyState } from '@/components/ui/empty-state'; import { Freshness } from '@/components/ui/freshness'; import { Pager } from '@/components/ui/pager'; import { SourceBadge, TableProvenance } from '@/components/ui/source-badge'; import { APPROVALS_PAGE_SIZE, approvalFacets, approvalStats, countApprovals, listApprovals, type ApprovalFilters, type FeedApprovalRow } from '@/lib/queries/approvals'; import { loadProvenance, toInfo } from '@/lib/queries/provenance'; import { fmtDate, fmtInt, truncate } from '@/lib/format'; import { pageInfo } from '@/lib/pagination'; import { str, int, withParams, type SP } from '@/lib/search-params'; export const metadata: Metadata = { title: 'Oncology approvals', description: 'Regulatory approval records for oncology drugs by authority and jurisdiction — dated, sourced, one record per application or DIN.', alternates: { canonical: '/approvals' }, }; // Filtered feed: rendered per request (searchParams); 600 s is the CDN/ISR hint shared by list pages. export const revalidate = 600; const STATUSES = ['approved', 'accelerated', 'conditional', 'withdrawn', 'superseded']; function monthKey(d: string | null): string { return d && /^\d{4}-\d{2}/.test(d) ? d.slice(0, 7) : 'undated'; } function monthLabel(k: string): string { return k === 'undated' ? 'Date not stated' : fmtDate(`${k}-01`, { year: 'numeric', month: 'long' }); } export default async function ApprovalsPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const f: ApprovalFilters = { authority: str(sp, 'authority'), jurisdiction: str(sp, 'jurisdiction'), cancer: str(sp, 'cancer'), status: STATUSES.includes(str(sp, 'status')) ? str(sp, 'status') : '', year: /^\d{4}$/.test(str(sp, 'year')) ? str(sp, 'year') : '', q: str(sp, 'q').slice(0, 100) }; const requestedPage = int(sp, 'page', 1, 1, 100_000); const [stats, facets, total] = await Promise.all([approvalStats(), approvalFacets(), countApprovals(f)]); const info = pageInfo(requestedPage, APPROVALS_PAGE_SIZE, total); const rows = total ? await listApprovals(f, info.page) : []; const prov = await loadProvenance(rows.map((r) => r.provenance_id)); const filtered = Object.values(f).some(Boolean); const href = (o: Record) => `/approvals${withParams({ ...f, page: info.page > 1 ? info.page : '' }, o)}`; // Group the page's rows by month, latest first (rows arrive sorted by approval_date desc). const groups: Array<{ key: string; rows: FeedApprovalRow[] }> = []; for (const r of rows) { const key = monthKey(r.approval_date); const g = groups[groups.length - 1]; if (g && g.key === key) g.rows.push(r); else groups.push({ key, rows: [r] }); } const latestUpdate = stats.byAuthority.reduce((m, a) => (a.updated_at && (!m || new Date(a.updated_at) > m) ? new Date(a.updated_at) : m), null); return (

Development pipeline → Methodology

{stats.total === 0 ? ( No regulatory connector has run on this environment yet. ) : ( <>
{[ { k: 'Approval records', v: stats.total }, { k: 'Distinct drugs', v: stats.distinctDrugs }, { k: 'Records naming a cancer', v: stats.withCancer }, { k: 'Dated in the last 12 months', v: stats.last12m }, ].map((t) => (

{t.k}

{fmtInt(t.v)}

))}
{stats.byAuthority.map((a) => ( ))}
Authority Jurisdiction Records Drugs In force Withdrawn / cancelled Last 12 months Latest dated record
{a.authority} {a.jurisdiction} {fmtInt(a.n)} {fmtInt(a.distinct_drugs)} {fmtInt(a.approved_like)} {fmtInt(a.withdrawn)} {fmtInt(a.last_12m)} {fmtDate(a.latest_date)}
{filtered ? ( Clear ) : null}
{rows.length === 0 ? (
{filtered ? 'Try fewer filters. Cancer filters only match records whose indication text named exactly one cancer; Health Canada records never name a cancer.' : 'No regulatory approval records have been ingested yet.'}
) : ( <> {groups.map((g) => { const first = g.rows[0]!; const caption = toInfo(prov.get(first.provenance_id)) ?? { sourceSlug: first.source_slug, sourceName: first.source_name }; const sources = new Set(g.rows.map((r) => r.source_slug)); return (

{monthLabel(g.key)} · {fmtInt(g.rows.length)} record{g.rows.length === 1 ? '' : 's'} on this page

}> {sources.size > 1 ? `${sources.size} sources in this month (hover a row badge for its dataset)` : 'authority, jurisdiction, dates and indication text as published'}
{g.rows.map((a) => ( ))}
Date Drug Authority · jurisdiction Cancer Indication (as published) Type Status Source
{fmtDate(a.approval_date)} {a.drug_name} {a.authority} {a.jurisdiction} {a.tumor_agnostic ? Tumor-agnostic : null} {a.cancer_slug ? ( {a.cancer_name} ) : !a.tumor_agnostic ? ( cancer not stated in this record ) : null} {truncate(a.indication, 140)} {a.approval_type ?? '—'}{a.application_number ? {a.application_number} : null} {a.source_status && a.source_status.toLowerCase() !== a.status ? source: {a.source_status} : null} {a.withdrawal_date ? since {fmtDate(a.withdrawal_date)} : null}
); })} href({ page: p > 1 ? p : '' })} label="Approval pages" noun="approval records" /> )}
A record is one authority's decision for one application/DIN; the same molecule appears once per jurisdiction and indication. Health Canada DPD does not publish indications — its records state the brand, DIN and ATC class only, and a cancelled or dormant DIN is the status of one product, not of the molecule. FDA cancer mappings come from label text and are flagged probabilistic on the drug page.
)}
); }