SPB Git

spb/cancerindex

Public
4.2 KB · 90 lines tsx
1import Link from 'next/link';2import { Badge, ClaimBadge, StatusBadge } from '@/components/ui/badge';3import { SourceBadge, TableProvenance } from '@/components/ui/source-badge';4import type { ApprovalRow } from '@/lib/queries/drugs';5import type { ProvRow } from '@/lib/queries/provenance';6import { toInfo } from '@/lib/queries/provenance';7import { fmtDate, fmtInt } from '@/lib/format';89/**10 * Jurisdiction-aware regulatory status (§13). Never a bare "approved". Approvals may come from11 * different authorities' datasets, so rows keep a compact badge with a dataset · version title;12 * the caption carries one full popover (first row's provenance) and the claim label.13 */14export function ApprovalsTable({ rows, prov, showDrug = true, showCancer = true }: { rows: ApprovalRow[]; prov: Map<number, ProvRow>; showDrug?: boolean; showCancer?: boolean }) {15  const first = rows[0];16  const caption = first ? (toInfo(prov.get(first.provenance_id)) ?? { sourceSlug: first.source_slug, sourceName: first.source_name }) : null;17  const sources = new Set(rows.map((r) => r.source_slug));18  return (19    <div>20      {caption ? (21        <TableProvenance p={caption} claim={<ClaimBadge kind="regulatory" />}>22          {fmtInt(rows.length)} approval record{rows.length === 1 ? '' : 's'}23          {sources.size > 1 ? ` from ${sources.size} sources (hover a row badge for its dataset)` : ''} · authority, jurisdiction and indication text as published.24        </TableProvenance>25      ) : null}26      <div className="ci-table-wrap">27        <table className="ci-table">28          <thead>29            <tr>30              {showDrug ? <th scope="col">Drug</th> : null}31              <th scope="col">Jurisdiction · authority</th>32              {showCancer ? <th scope="col">Cancer</th> : null}33              <th scope="col">Indication</th>34              <th scope="col">Status</th>35              <th scope="col">Approval date</th>36              <th scope="col">Source</th>37            </tr>38          </thead>39          <tbody>40            {rows.map((a) => (41              <tr key={a.id}>42                {showDrug ? (43                  <td>44                    <Link className="ci-link" href={`/drug/${a.drug_slug}`}>45                      {a.drug_name}46                    </Link>47                  </td>48                ) : null}49                <td className="whitespace-nowrap">50                  <span className="ci-mono font-medium">{a.jurisdiction}</span> <span className="text-ink-3">{a.authority}</span>51                </td>52                {showCancer ? (53                  <td>54                    {a.tumor_agnostic ? <Badge tone="accent">Tumor-agnostic</Badge> : null}55                    {a.cancer_slug ? (56                      <Link className="ci-link" href={`/cancer/${a.cancer_slug}`}>57                        {a.cancer_name}58                      </Link>59                    ) : !a.tumor_agnostic ? (60                      <span className="text-ink-3">—</span>61                    ) : null}62                  </td>63                ) : null}64                <td className="min-w-[280px] max-w-[520px] text-[12.5px]">65                  {a.indication}66                  <span className="mt-0.5 flex flex-wrap gap-1">67                    {a.line_of_therapy ? <Badge tone="outline">{a.line_of_therapy}</Badge> : null}68                    {a.disease_stage ? <Badge tone="outline">{a.disease_stage}</Badge> : null}69                    {a.accelerated ? <Badge tone="warn">accelerated</Badge> : null}70                    {a.conditional ? <Badge tone="warn">conditional</Badge> : null}71                    {a.biomarker_ids.length ? <Badge tone="outline">biomarker-restricted</Badge> : null}72                  </span>73                </td>74                <td>75                  <StatusBadge status={a.status} />76                  {a.withdrawal_date ? <span className="block text-[11px] text-danger">withdrawn {fmtDate(a.withdrawal_date)}</span> : null}77                </td>78                <td className="whitespace-nowrap">{fmtDate(a.approval_date)}</td>79                <td>80                  <SourceBadge compact p={toInfo(prov.get(a.provenance_id)) ?? { sourceSlug: a.source_slug, sourceName: a.source_name }} />81                </td>82              </tr>83            ))}84          </tbody>85        </table>86      </div>87    </div>88  );89}90
Files · 602dc111f3dd7d7dec082e01832909f07dca7bd3
Menu

Theme