fix: prevent immediate elo update on listing selection

This commit is contained in:
Stijnvandenbroek
2026-03-06 15:04:27 +00:00
parent 535a09fd75
commit f8c61918d5

View File

@@ -9,7 +9,7 @@ interface Toast {
export default function CompareView() { export default function CompareView() {
const [matchup, setMatchup] = useState<Matchup | null>(null); const [matchup, setMatchup] = useState<Matchup | null>(null);
const [result, setResult] = useState<CompareResult | null>(null); const [selected, setSelected] = useState<{ winner: Listing; loser: Listing } | null>(null);
const [toasts, setToasts] = useState<Toast[]>([]); const [toasts, setToasts] = useState<Toast[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
@@ -19,7 +19,7 @@ export default function CompareView() {
const fetchMatchup = useCallback(async () => { const fetchMatchup = useCallback(async () => {
setLoading(true); setLoading(true);
setResult(null); setSelected(null);
setError(null); setError(null);
try { try {
const m = await api.getMatchup(); const m = await api.getMatchup();
@@ -35,18 +35,26 @@ export default function CompareView() {
fetchMatchup(); fetchMatchup();
}, [fetchMatchup]); }, [fetchMatchup]);
const handlePick = async (winner: Listing, loser: Listing) => { const handlePick = (winner: Listing, loser: Listing) => {
if (submitting) return; setSelected({ winner, loser });
};
const handleNext = async () => {
if (!selected || submitting) return;
setSubmitting(true); setSubmitting(true);
try { try {
const res = await api.submitComparison(winner.global_id, loser.global_id); const res = await api.submitComparison(selected.winner.global_id, selected.loser.global_id);
setResult(res);
setComparisonCount((c) => c + 1); setComparisonCount((c) => c + 1);
// Add toast // Add toast
const id = ++toastId.current; const id = ++toastId.current;
setToasts((prev) => [...prev, { id, result: res }]); setToasts((prev) => [...prev, { id, result: res }]);
setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), 3000); setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), 3000);
// Load next pair
setSelected(null);
const m = await api.getMatchup();
setMatchup(m);
} catch (e) { } catch (e) {
setError(e instanceof Error ? e.message : "Failed to submit comparison"); setError(e instanceof Error ? e.message : "Failed to submit comparison");
} finally { } finally {
@@ -95,13 +103,13 @@ export default function CompareView() {
listing={matchup.listing_a} listing={matchup.listing_a}
onClick={() => handlePick(matchup.listing_a, matchup.listing_b)} onClick={() => handlePick(matchup.listing_a, matchup.listing_b)}
disabled={submitting} disabled={submitting}
highlight={result?.winner_id === matchup.listing_a.global_id} highlight={selected?.winner.global_id === matchup.listing_a.global_id}
/> />
<ListingCard <ListingCard
listing={matchup.listing_b} listing={matchup.listing_b}
onClick={() => handlePick(matchup.listing_b, matchup.listing_a)} onClick={() => handlePick(matchup.listing_b, matchup.listing_a)}
disabled={submitting} disabled={submitting}
highlight={result?.winner_id === matchup.listing_b.global_id} highlight={selected?.winner.global_id === matchup.listing_b.global_id}
/> />
</div> </div>
@@ -112,12 +120,13 @@ export default function CompareView() {
> >
Skip Skip
</button> </button>
{result && ( {selected && (
<button <button
onClick={fetchMatchup} onClick={handleNext}
className="px-6 py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700 transition-colors" disabled={submitting}
className="px-6 py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700 transition-colors disabled:opacity-50"
> >
Next pair {submitting ? "Submitting..." : "Next pair →"}
</button> </button>
)} )}
</div> </div>
@@ -138,7 +147,7 @@ export default function CompareView() {
<p className="text-xs text-slate-500">Comparison recorded</p> <p className="text-xs text-slate-500">Comparison recorded</p>
</div> </div>
</div> </div>
<div className="flex items-center justify-between mt-2 text-sm"> <div className="flex items-center justify-between gap-4 mt-2 text-sm">
<span className="text-green-600 font-bold"> <span className="text-green-600 font-bold">
Winner: {t.result.new_winner_elo.toFixed(0)}{" "} Winner: {t.result.new_winner_elo.toFixed(0)}{" "}
<span className="text-green-500 text-xs">(+{t.result.elo_change.toFixed(1)})</span> <span className="text-green-500 text-xs">(+{t.result.elo_change.toFixed(1)})</span>