SPB Git forge

spb/cancerindex

Public
37commits 1branches 0releases
2.9 MBsize
maindefault branch
10 days agolast push
TypeScript 97.2% SQL 1.5% CSS 0.6% JavaScript 0.5%
4.0 KB · 93 lines tsx
Raw Blame History
1import Link from 'next/link';2import { Badge } from '@/components/ui/badge';3import { EPI_METRIC_LABEL } from '@/lib/queries/epidemiology';4import type { CoverageMatrixRow } from '@/lib/queries/explorer';5import { fmtDate, fmtInt, humanize, unitLabel } from '@/lib/format';67/**8 * Coverage matrix: what exists, per metric × geography × sex × age group × source × standard population,9 * with the year span, the number of distinct years, observations and cancers. Each row links to the10 * explorer with the same dimensions so a gap can be checked in one click.11 */12export function CoverageTable({ rows, cancers, compact = false }: { rows: CoverageMatrixRow[]; cancers?: string[]; compact?: boolean }) {13  if (rows.length === 0) return null;14  const hrefFor = (r: CoverageMatrixRow) => {15    const qs = new URLSearchParams({ metric: r.metric, geography: r.geography_slug, sex: r.sex, age: r.age_group, from: String(r.year_from), to: String(r.year_to) });16    if (cancers && cancers.length > 0) qs.set('cancers', cancers.join(','));17    return `/explore?${qs.toString()}`;18  };19  return (20    <div className="ci-table-wrap">21      <table className="ci-table">22        <thead>23          <tr>24            <th scope="col">Metric</th>25            <th scope="col">Geography</th>26            <th scope="col">Sex</th>27            <th scope="col">Age</th>28            <th scope="col">Source</th>29            <th scope="col">Standard population</th>30            <th scope="col">Years</th>31            <th scope="col" className="num">32              Distinct years33            </th>34            <th scope="col" className="num">35              Observations36            </th>37            {compact ? null : (38              <th scope="col" className="num">39                Cancers40              </th>41            )}42            <th scope="col">Type</th>43            {compact ? null : <th scope="col">Updated</th>}44            <th scope="col">45              <span className="sr-only">Open</span>46            </th>47          </tr>48        </thead>49        <tbody>50          {rows.map((r, i) => (51            <tr key={`${r.metric}|${r.geography_id}|${r.sex}|${r.age_group}|${r.source_slug}|${r.standard_population ?? ''}|${i}`}>52              <td className="whitespace-nowrap">53                {EPI_METRIC_LABEL[r.metric] ?? humanize(r.metric)} <span className="text-[11.5px] text-ink-3">({unitLabel(r.unit)})</span>54              </td>55              <td>56                <Link className="ci-link" href={`/country/${r.geography_slug}`}>57                  {r.geography_name}58                </Link>59                {r.iso3 ? <span className="ci-mono ml-1 text-[11px] text-ink-3">{r.iso3}</span> : null}60              </td>61              <td>{r.sex === 'all' ? 'Both' : humanize(r.sex)}</td>62              <td>{r.age_group === 'all' ? 'All ages' : r.age_group}</td>63              <td>64                <Link className="ci-src" href={`/source/${r.source_slug}`} title={r.source_name}>65                  {r.source_slug}66                </Link>67              </td>68              <td className="max-w-[220px] text-[12px] text-ink-3">{r.standard_population ?? '—'}</td>69              <td className="ci-num whitespace-nowrap">{r.year_from === r.year_to ? r.year_from : `${r.year_from}–${r.year_to}`}</td>70              <td className="num">{fmtInt(r.years)}</td>71              <td className="num">{fmtInt(r.observations)}</td>72              {compact ? null : <td className="num">{fmtInt(r.n_cancers)}</td>}73              <td>74                {r.estimate_types.map((t) => (75                  <Badge key={t} tone={t === 'observed' ? 'ok' : 'warn'} className="mr-1">76                    {t}77                  </Badge>78                ))}79              </td>80              {compact ? null : <td className="whitespace-nowrap text-[12px] text-ink-3">{fmtDate(r.last_updated)}</td>}81              <td>82                <Link className="ci-link whitespace-nowrap text-[12px]" href={hrefFor(r)}>83                  Open →84                </Link>85              </td>86            </tr>87          ))}88        </tbody>89      </table>90    </div>91  );92}93