SPB Git

spb/cancerindex

Public
3.3 KB · 78 lines tsx
1import Link from 'next/link';2import { Badge, ClaimBadge, StatusBadge } from '@/components/ui/badge';3import { SourceBadge } 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 } from '@/lib/format';89/** Jurisdiction-aware regulatory status (§13). Never a bare "approved". */10export function ApprovalsTable({ rows, prov, showDrug = true, showCancer = true }: { rows: ApprovalRow[]; prov: Map<number, ProvRow>; showDrug?: boolean; showCancer?: boolean }) {11  return (12    <div className="ci-table-wrap">13      <table className="ci-table">14        <thead>15          <tr>16            {showDrug ? <th>Drug</th> : null}17            <th>Jurisdiction · authority</th>18            {showCancer ? <th>Cancer</th> : null}19            <th>Indication</th>20            <th>Status</th>21            <th>Approval date</th>22            <th>Source</th>23          </tr>24        </thead>25        <tbody>26          {rows.map((a) => (27            <tr key={a.id}>28              {showDrug ? (29                <td>30                  <Link className="ci-link" href={`/drug/${a.drug_slug}`}>31                    {a.drug_name}32                  </Link>33                </td>34              ) : null}35              <td className="whitespace-nowrap">36                <span className="ci-mono font-medium">{a.jurisdiction}</span> <span className="text-ink-3">{a.authority}</span>37              </td>38              {showCancer ? (39                <td>40                  {a.tumor_agnostic ? <Badge tone="accent">Tumor-agnostic</Badge> : null}41                  {a.cancer_slug ? (42                    <Link className="ci-link" href={`/cancer/${a.cancer_slug}`}>43                      {a.cancer_name}44                    </Link>45                  ) : !a.tumor_agnostic ? (46                    <span className="text-ink-3">—</span>47                  ) : null}48                </td>49              ) : null}50              <td className="min-w-[280px] max-w-[520px] text-[12.5px]">51                {a.indication}52                <span className="mt-0.5 flex flex-wrap gap-1">53                  {a.line_of_therapy ? <Badge tone="outline">{a.line_of_therapy}</Badge> : null}54                  {a.disease_stage ? <Badge tone="outline">{a.disease_stage}</Badge> : null}55                  {a.accelerated ? <Badge tone="warn">accelerated</Badge> : null}56                  {a.conditional ? <Badge tone="warn">conditional</Badge> : null}57                  {a.biomarker_ids.length ? <Badge tone="outline">biomarker-restricted</Badge> : null}58                </span>59              </td>60              <td>61                <StatusBadge status={a.status} />62                {a.withdrawal_date ? <span className="block text-[11px] text-danger">withdrawn {fmtDate(a.withdrawal_date)}</span> : null}63              </td>64              <td className="whitespace-nowrap">{fmtDate(a.approval_date)}</td>65              <td>66                <span className="inline-flex gap-1">67                  <SourceBadge p={toInfo(prov.get(a.provenance_id)) ?? { sourceSlug: a.source_slug, sourceName: a.source_name }} />68                  <ClaimBadge kind="regulatory" />69                </span>70              </td>71            </tr>72          ))}73        </tbody>74      </table>75    </div>76  );77}78
Files · 36d464dcc8d9fe84217ecbfd89a225759f5f0c06
Menu

Theme