110 lines
6.0 KiB
TypeScript
110 lines
6.0 KiB
TypeScript
import React, { useState } from 'react';
|
|
|
|
type HighlightMode = 'none' | 'bus' | 'club' | 'cond_club_bus' | 'cond_bus_club' | 'or_bus_club';
|
|
|
|
const ProbabilityTableWidget: React.FC = () => {
|
|
const [highlight, setHighlight] = useState<HighlightMode>('none');
|
|
|
|
const data = {
|
|
bus_club: 36, bus_noClub: 24,
|
|
noBus_club: 30, noBus_noClub: 30
|
|
};
|
|
|
|
const totals = {
|
|
bus: data.bus_club + data.bus_noClub, // 60
|
|
noBus: data.noBus_club + data.noBus_noClub, // 60
|
|
club: data.bus_club + data.noBus_club, // 66
|
|
noClub: data.bus_noClub + data.noBus_noClub, // 54
|
|
total: 120
|
|
};
|
|
|
|
const getCellClass = (cell: string) => {
|
|
const base = "p-4 text-center border font-mono font-bold transition-colors duration-300 ";
|
|
|
|
// Logic for highlighting based on mode
|
|
let isNum = false;
|
|
let isDenom = false;
|
|
|
|
if (highlight === 'bus') {
|
|
if (cell === 'bus_total') isNum = true;
|
|
if (cell === 'grand_total') isDenom = true;
|
|
} else if (highlight === 'club') {
|
|
if (cell === 'club_total') isNum = true;
|
|
if (cell === 'grand_total') isDenom = true;
|
|
} else if (highlight === 'cond_club_bus') {
|
|
if (cell === 'bus_club') isNum = true;
|
|
if (cell === 'bus_total') isDenom = true;
|
|
} else if (highlight === 'cond_bus_club') {
|
|
if (cell === 'bus_club') isNum = true;
|
|
if (cell === 'club_total') isDenom = true;
|
|
} else if (highlight === 'or_bus_club') {
|
|
if (['bus_club', 'bus_noClub', 'noBus_club'].includes(cell)) isNum = true;
|
|
if (cell === 'grand_total') isDenom = true;
|
|
}
|
|
|
|
if (isNum) return base + "bg-emerald-100 text-emerald-800 border-emerald-300";
|
|
if (isDenom) return base + "bg-indigo-100 text-indigo-800 border-indigo-300";
|
|
return base + "bg-white border-slate-200 text-slate-600";
|
|
};
|
|
|
|
const explanation = () => {
|
|
switch(highlight) {
|
|
case 'bus': return { title: "P(Bus)", math: `${totals.bus} / ${totals.total} = 0.50` };
|
|
case 'club': return { title: "P(Club)", math: `${totals.club} / ${totals.total} = 0.55` };
|
|
case 'cond_club_bus': return { title: "P(Club | Bus)", math: `${data.bus_club} / ${totals.bus} = 0.60`, sub: "Given Bus, restrict to Bus row." };
|
|
case 'cond_bus_club': return { title: "P(Bus | Club)", math: `${data.bus_club} / ${totals.club} ≈ 0.55`, sub: "Given Club, restrict to Club column." };
|
|
case 'or_bus_club': return { title: "P(Bus OR Club)", math: `(${totals.bus} + ${totals.club} - ${data.bus_club}) / ${totals.total} = ${totals.bus+totals.club-data.bus_club}/${totals.total} = 0.75`, sub: "Add totals, subtract overlap." };
|
|
default: return { title: "Select a Probability", math: "---" };
|
|
}
|
|
};
|
|
|
|
const exp = explanation();
|
|
|
|
return (
|
|
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
|
|
<div className="flex flex-wrap gap-2 mb-6 justify-center">
|
|
<button onClick={() => setHighlight('bus')} className="px-3 py-1 bg-slate-100 hover:bg-slate-200 rounded text-sm font-bold text-slate-700">P(Bus)</button>
|
|
<button onClick={() => setHighlight('club')} className="px-3 py-1 bg-slate-100 hover:bg-slate-200 rounded text-sm font-bold text-slate-700">P(Club)</button>
|
|
<button onClick={() => setHighlight('cond_club_bus')} className="px-3 py-1 bg-indigo-100 hover:bg-indigo-200 rounded text-sm font-bold text-indigo-700">P(Club | Bus)</button>
|
|
<button onClick={() => setHighlight('cond_bus_club')} className="px-3 py-1 bg-indigo-100 hover:bg-indigo-200 rounded text-sm font-bold text-indigo-700">P(Bus | Club)</button>
|
|
<button onClick={() => setHighlight('or_bus_club')} className="px-3 py-1 bg-emerald-100 hover:bg-emerald-200 rounded text-sm font-bold text-emerald-700">P(Bus OR Club)</button>
|
|
</div>
|
|
|
|
<div className="overflow-hidden rounded-lg border border-slate-200 mb-6">
|
|
<div className="grid grid-cols-4 bg-slate-50 border-b border-slate-200">
|
|
<div className="p-3 text-center text-xs font-bold text-slate-400 uppercase"></div>
|
|
<div className="p-3 text-center text-xs font-bold text-slate-500 uppercase">Club</div>
|
|
<div className="p-3 text-center text-xs font-bold text-slate-500 uppercase">No Club</div>
|
|
<div className="p-3 text-center text-xs font-bold text-slate-800 uppercase">Total</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-4">
|
|
<div className="p-4 flex items-center justify-center font-bold text-slate-600 bg-slate-50 border-r border-slate-200">Bus</div>
|
|
<div className={getCellClass('bus_club')}>{data.bus_club}</div>
|
|
<div className={getCellClass('bus_noClub')}>{data.bus_noClub}</div>
|
|
<div className={getCellClass('bus_total')}>{totals.bus}</div>
|
|
|
|
<div className="p-4 flex items-center justify-center font-bold text-slate-600 bg-slate-50 border-r border-slate-200 border-t border-slate-200">No Bus</div>
|
|
<div className={getCellClass('noBus_club')}>{data.noBus_club}</div>
|
|
<div className={getCellClass('noBus_noClub')}>{data.noBus_noClub}</div>
|
|
<div className={getCellClass('noBus_total')}>{totals.noBus}</div>
|
|
|
|
<div className="p-4 flex items-center justify-center font-bold text-slate-900 bg-slate-100 border-r border-slate-200 border-t border-slate-200">Total</div>
|
|
<div className={getCellClass('club_total')}>{totals.club}</div>
|
|
<div className={getCellClass('noClub_total')}>{totals.noClub}</div>
|
|
<div className={getCellClass('grand_total')}>{totals.total}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-slate-50 p-4 rounded-xl text-center">
|
|
<h4 className="text-sm font-bold text-slate-500 uppercase mb-2">{exp.title}</h4>
|
|
<div className="text-2xl font-mono font-bold text-slate-800 mb-1">
|
|
{exp.math}
|
|
</div>
|
|
{exp.sub && <p className="text-xs text-slate-400">{exp.sub}</p>}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ProbabilityTableWidget; |