import type { Metadata } from 'next'; import Link from 'next/link'; import { PageHeader, Section, Note } from '@/components/ui/section'; import { Badge, ClaimBadge } 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 } from '@/components/ui/source-badge'; import { PIPELINE_FUNNEL, PIPELINE_PAGE_SIZE, PIPELINE_STAGES, countPipelineRows, listPipelineRows, pipelineSourceSlugs, pipelineSummary, pipelineTopDrugsPerStage, topLevelCancerOptions, type PipelineRow, type PipelineStage } from '@/lib/queries/approvals'; import { fmtDate, fmtInt, phaseLabel } from '@/lib/format'; import { pageInfo } from '@/lib/pagination'; import { str, int, withParams, type SP } from '@/lib/search-params'; export const metadata: Metadata = { title: 'Drug development pipeline', description: 'Development stage of oncology drugs per top-level cancer, derived from registered interventional trials and jurisdiction-aware approvals.', alternates: { canonical: '/pipeline' }, }; export const revalidate = 600; const STAGE_LABEL: Record = { phase_not_stated: 'Phase not stated', phase1: 'Phase 1', phase2: 'Phase 2', phase3: 'Phase 3', phase4: 'Phase 4', approved: 'Approved', withdrawn: 'Withdrawn', }; function StageBadge({ stage }: { stage: PipelineStage }) { const tone = stage === 'approved' ? 'ok' : stage === 'withdrawn' ? 'danger' : stage === 'phase_not_stated' ? 'outline' : 'neutral'; return {STAGE_LABEL[stage] ?? stage}; } /** * Funnel: one server-rendered SVG bar per stage (phase 1 → approved), width ∝ number of drugs, * with the representative drugs (most active trials) listed beside each bar. */ function Funnel({ stages, top, hrefFor }: { stages: Array<{ stage: PipelineStage; drugs: number; active_trials: number }>; top: Map; hrefFor: (stage: PipelineStage) => string }) { const funnel = PIPELINE_FUNNEL.map((s) => stages.find((x) => x.stage === s) ?? { stage: s, drugs: 0, active_trials: 0 }); const max = Math.max(...funnel.map((s) => s.drugs), 1); return (
    {funnel.map((s) => { const w = Math.max(s.drugs > 0 ? 1 : 0, Math.round((s.drugs / max) * 100)); const reps = top.get(s.stage) ?? []; return (
  1. {STAGE_LABEL[s.stage]}

    {fmtInt(s.drugs)} drug{s.drugs === 1 ? '' : 's'} · {fmtInt(s.active_trials)} active trials

    {reps.length ? ( reps.map((r, i) => ( {i > 0 ? ', ' : ''} {r.drug_name} )) ) : ( no drug at this stage )}

  2. ); })}
); } export default async function PipelinePage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const cancerSlug = str(sp, 'cancer'); const stage = (PIPELINE_STAGES as readonly string[]).includes(str(sp, 'stage')) ? (str(sp, 'stage') as PipelineStage) : ''; const requestedPage = int(sp, 'page', 1, 1, 100_000); const options = await topLevelCancerOptions(); const cancer = options.find((c) => c.slug === cancerSlug) ?? null; const scopeId = cancer?.id ?? null; const [summary, top, total, sources] = await Promise.all([pipelineSummary(scopeId), pipelineTopDrugsPerStage(scopeId, 5), countPipelineRows(scopeId, stage), pipelineSourceSlugs()]); const info = pageInfo(requestedPage, PIPELINE_PAGE_SIZE, total); const rows = total ? await listPipelineRows(scopeId, stage, info.page) : []; const current = { cancer: cancer?.slug ?? '', stage, page: info.page > 1 ? info.page : '' }; const href = (o: Record) => `/pipeline${withParams(current, o)}`; const side = summary.stages.filter((s) => s.stage === 'withdrawn' || s.stage === 'phase_not_stated'); return (

{summary.formulaVersion ? {summary.formulaVersion} : null} Stage rules Approvals feed →

{cancer || stage ? ( Clear ) : null}
{summary.drugs === 0 ? (
{cancer ? `No drug is linked to ${cancer.canonical_name} through a registered interventional trial or an approval record yet.` : 'The pipeline has not been computed on this environment yet (pnpm cix intel).'}
) : ( <>
href({ stage: s, page: '' })} /> {side.some((s) => s.drugs > 0) ? (

Outside the funnel:{' '} {side .filter((s) => s.drugs > 0) .map((s, i) => ( {i > 0 ? ' · ' : ''} {STAGE_LABEL[s.stage]} {' '} {fmtInt(s.drugs)} ))} . "Withdrawn" = every approval record for the scope is withdrawn or superseded; "phase not stated" = trials exist but none states a phase.

) : null}
{sources.map((s) => ( ))} {summary.formulaVersion ? {summary.formulaVersion} : null}
{rows.length === 0 ? ( No drug at this stage for the selected scope. ) : ( <>
{rows.map((r) => ( ))}
Drug Stage Max phase Active Recruiting Phase 3 Total trials Approvals Jurisdictions First approval First trial
{r.drug_name} {r.max_phase ? phaseLabel(r.max_phase) : '—'} {fmtInt(r.active_trials)} {fmtInt(r.recruiting_trials)} {fmtInt(r.phase3_trials)} {fmtInt(r.total_trials)} {fmtInt(r.approvals)} {r.jurisdictions.length ? r.jurisdictions.join(', ') : '—'} {fmtDate(r.first_approval_date)} {r.first_trial_date ? (r.first_trial_date.length >= 10 ? fmtDate(r.first_trial_date) : r.first_trial_date) : '—'}
href({ page: p > 1 ? p : '' })} label="Pipeline pages" noun="drugs" /> )}
Stages describe registered activity and ingested regulatory records, not efficacy. Only ingested jurisdictions (currently US and Canada) can place a drug at "approved"; trial phases are as registered by sponsors. Nothing here is a treatment recommendation.
)}
); }