feat: add viewer voting on user answers with leaderboard scoring

Viewers can now vote for their favourite audience answers during the
30-second voting window. Votes are persisted to the DB at round end
and aggregated as SUM(votes) in the JUGADORES leaderboard.

- db.ts: add persistUserAnswerVotes(); switch getPlayerScores() to SUM(votes)
- game.ts: add userAnswerVotes to RoundState; persist votes before saveRound
- server.ts: add userAnswerVoters map + /api/vote/respuesta endpoint
- frontend.tsx: add userAnswerVotes type; vote state/handler in App; ▲ buttons in Arena
- frontend.css: flex layout for user-answer rows; user-vote-btn styles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 18:26:09 +01:00
parent fe5bb5a5c2
commit 40c919fc64
5 changed files with 182 additions and 12 deletions

View File

@@ -68,6 +68,7 @@ export type RoundState = {
viewerVotesB?: number;
viewerVotingEndsAt?: number;
userAnswers?: { username: string; text: string }[];
userAnswerVotes?: Record<string, number>;
};
export type GameState = {
@@ -266,7 +267,7 @@ export async function callVote(
return cleaned.startsWith("A") ? "A" : "B";
}
import { saveRound, getNextPendingQuestion, markQuestionUsed } from "./db.ts";
import { saveRound, getNextPendingQuestion, markQuestionUsed, persistUserAnswerVotes } from "./db.ts";
// ── Game loop ───────────────────────────────────────────────────────────────
@@ -498,6 +499,11 @@ export async function runGame(
continue;
}
// Persist votes for user answers
if (round.userAnswerVotes && round.userAnswers && round.userAnswers.length > 0) {
persistUserAnswerVotes(round.num, round.userAnswerVotes);
}
// Archive round
saveRound(round);
state.completed = [...state.completed, round];