diff --git a/wwwroot/app.js b/wwwroot/app.js index d5d2390..c19abf6 100644 --- a/wwwroot/app.js +++ b/wwwroot/app.js @@ -367,14 +367,38 @@ function bindNavButtons() { const finalizeBtn = $("finalize-votes"); if (finalizeBtn) { + const finalizeVotes = async (desired) => { + await api.finalizeVotes(desired); + state.votesFinal = desired; + renderPhasePill(); + renderVotes(); + toast(desired ? t("vote.finalize") : t("vote.unfinalize")); + }; + + const missingVotes = () => { + const votedIds = new Set((state.myVotes ?? []).map((v) => v.suggestionId)); + return (state.allSuggestions ?? []).filter((s) => !votedIds.has(s.id)); + }; + finalizeBtn.addEventListener("click", async () => { try { const desired = !state.votesFinal; - await api.finalizeVotes(desired); - state.votesFinal = desired; - renderPhasePill(); - renderVotes(); - toast(desired ? t("vote.finalize") : t("vote.unfinalize")); + if (desired) { + const missing = missingVotes(); + if (missing.length > 0) { + openConfirmModal({ + title: t("vote.finalizeMissingTitle"), + body: t("vote.finalizeMissingBody", { count: missing.length }), + confirmLabel: t("vote.finalizeMissingConfirm"), + onConfirm: async (close) => { + await finalizeVotes(desired); + close(); + }, + }); + return; + } + } + await finalizeVotes(desired); } catch (err) { toast(err.message, true); } diff --git a/wwwroot/js/i18n.js b/wwwroot/js/i18n.js index b8e3451..e35b382 100644 --- a/wwwroot/js/i18n.js +++ b/wwwroot/js/i18n.js @@ -88,6 +88,9 @@ const translations = { "vote.unfinalize": "Edit votes", "vote.finalHint": "Finalize when you’re done. You can unfinalize to change scores.", "vote.waitAdmin": "Waiting for admin to unlock results.", + "vote.finalizeMissingTitle": "Finalize with missing votes?", + "vote.finalizeMissingBody": "You still have {count} game(s) without a score. Finalizing will mark you as done while those stay unrated.", + "vote.finalizeMissingConfirm": "Finalize anyway", "results.rank": "Rank", "results.game": "Game", @@ -250,6 +253,9 @@ const translations = { "vote.unfinalize": "Abstimmung bearbeiten", "vote.finalHint": "Schließe ab, wenn du fertig bist. Zum Ändern wieder öffnen.", "vote.waitAdmin": "Warten, bis der Admin die Ergebnisse freigibt.", + "vote.finalizeMissingTitle": "Mit fehlenden Stimmen abschließen?", + "vote.finalizeMissingBody": "Für {count} Spiel(e) fehlt noch eine Wertung. Beim Abschließen gilt deine Abstimmung als fertig, obwohl diese Spiele unbewertet bleiben.", + "vote.finalizeMissingConfirm": "Trotzdem abschließen", "results.rank": "Rang", "results.game": "Spiel",