| 97 |
97 |
</div> |
| 98 |
98 |
); |
| 99 |
99 |
} |
|
100 |
+ |
|
101 |
+/** Gene-centric view: one compact row per cohort (used on /gene/[symbol]); denominators stay mandatory. */ |
|
102 |
+export function GeneFrequencyTable({ rows, prov }: { rows: FreqRow[]; prov: Map<number, ProvRow> }) { |
|
103 |
+ const sorted = [...rows].sort((a, b) => b.frequency - a.frequency); |
|
104 |
+ return ( |
|
105 |
+ <div className="ci-table-wrap"> |
|
106 |
+ <table className="ci-table"> |
|
107 |
+ <thead> |
|
108 |
+ <tr> |
|
109 |
+ <th>Cohort</th> |
|
110 |
+ <th>Mapped cancer</th> |
|
111 |
+ <th>Alteration</th> |
|
112 |
+ <th className="num">Affected (n)</th> |
|
113 |
+ <th className="num">Profiled (n)</th> |
|
114 |
+ <th className="num">Frequency (%)</th> |
|
115 |
+ <th className="num">Rank in cohort</th> |
|
116 |
+ <th>Source</th> |
|
117 |
+ </tr> |
|
118 |
+ </thead> |
|
119 |
+ <tbody> |
|
120 |
+ {sorted.map((r) => ( |
|
121 |
+ <tr key={r.id}> |
|
122 |
+ <td> |
|
123 |
+ <span className="font-medium">{r.cohort_name}</span> <span className="ci-mono text-[11.5px] text-ink-3">{r.study_id}</span> |
|
124 |
+ </td> |
|
125 |
+ <td> |
|
126 |
+ {r.cancer_slug ? ( |
|
127 |
+ <> |
|
128 |
+ <Link className="ci-link" href={`/cancer/${r.cancer_slug}`}> |
|
129 |
+ {r.cancer_name} |
|
130 |
+ </Link>{' '} |
|
131 |
+ <MatchBadge matchType={r.cancer_match_type} /> |
|
132 |
+ </> |
|
133 |
+ ) : ( |
|
134 |
+ <span className="text-ink-3">unmapped</span> |
|
135 |
+ )} |
|
136 |
+ </td> |
|
137 |
+ <td> |
|
138 |
+ <Badge tone="outline">{humanize(r.alteration_type)}</Badge> |
|
139 |
+ </td> |
|
140 |
+ <td className="num">{fmtInt(r.cases_affected)}</td> |
|
141 |
+ <td className="num">{fmtInt(r.cases_profiled)}</td> |
|
142 |
+ <td className="num font-medium">{fmtPct(r.frequency, 1)}</td> |
|
143 |
+ <td className="num text-ink-3">{r.rank ?? '—'}</td> |
|
144 |
+ <td> |
|
145 |
+ <span className="inline-flex gap-1"> |
|
146 |
+ <SourceBadge p={toInfo(prov.get(r.provenance_id)) ?? { sourceSlug: r.source_slug, sourceName: r.source_name }} /> |
|
147 |
+ <ClaimBadge kind="observed" /> |
|
148 |
+ </span> |
|
149 |
+ </td> |
|
150 |
+ </tr> |
|
151 |
+ ))} |
|
152 |
+ </tbody> |
|
153 |
+ </table> |
|
154 |
+ <p className="mt-1 text-[12px] text-ink-3">frequency = affected / profiled, as published by each cohort; cohorts are not pooled.</p> |
|
155 |
+ </div> |
|
156 |
+ ); |
|
157 |
+} |
| 100 |
158 |
|