diff --git a/app/features/sendouq-match/components/RematchVotePanel.tsx b/app/features/sendouq-match/components/RematchVotePanel.tsx index 2358a7e4f..9e809af82 100644 --- a/app/features/sendouq-match/components/RematchVotePanel.tsx +++ b/app/features/sendouq-match/components/RematchVotePanel.tsx @@ -38,7 +38,9 @@ export function RematchVotePanel({ members.map((m) => m.id), ).length; - const voteResolved = RejoinVote.result(votes).type === "RESOLVED"; + const voteResult = RejoinVote.result(votes); + const voteResolved = voteResult.type === "RESOLVED"; + const voteFailed = voteResult.type === "FAILED"; const viewerVotedYes = RejoinVote.userContinueStatus(votes, viewerUserId) === true; const viewerVotedNo = @@ -47,9 +49,11 @@ export function RematchVotePanel({ return (
- {voteResolved - ? t("q:match.rematch.resolved", { count: currentRoundSize }) - : t("q:match.rematch.prompt", { count: currentRoundSize })} + {voteFailed + ? t("q:match.rematch.fizzled") + : voteResolved + ? t("q:match.rematch.resolved", { count: currentRoundSize }) + : t("q:match.rematch.prompt", { count: currentRoundSize })}
- ) : viewerVotedNo ? null : ( + ) : voteFailed || viewerVotedNo ? null : (
{ continuingUserIds: [1, 3], }); }); + + test("fails when fewer than two members want to continue", () => { + expect( + RejoinVote.result([ + { userId: 1, isContinuing: true }, + { userId: 2, isContinuing: false }, + { userId: 3, isContinuing: false }, + { userId: 4, isContinuing: false }, + ]), + ).toEqual({ type: "FAILED" }); + }); }); describe("RejoinVote.userContinueStatus()", () => { diff --git a/app/features/sendouq-match/core/RejoinVote.ts b/app/features/sendouq-match/core/RejoinVote.ts index 2ed597e55..8d91438f0 100644 --- a/app/features/sendouq-match/core/RejoinVote.ts +++ b/app/features/sendouq-match/core/RejoinVote.ts @@ -7,21 +7,29 @@ export interface RejoinVote { isContinuing: boolean; } +const MIN_CONTINUING_GROUP_SIZE = 2; + /** - * Resolves the overall vote state. ONGOING until every member of a full - * group has cast a vote, then returns the ids of those who chose to continue. + * Resolves the overall vote state. ONGOING until every member of a full group + * has cast a vote, then RESOLVED with the ids of those who chose to continue, + * or FAILED if too few want to continue to form a viable group. */ -// xxx: what about FAILED? export function result(votes: RejoinVote[]) { if (votes.length !== FULL_GROUP_SIZE) { return { type: "ONGOING" as const }; } - const willContinue = votes.filter((vote) => vote.isContinuing); + const continuingUserIds = votes + .filter((vote) => vote.isContinuing) + .map((vote) => vote.userId); + + if (continuingUserIds.length < MIN_CONTINUING_GROUP_SIZE) { + return { type: "FAILED" as const }; + } return { type: "RESOLVED" as const, - continuingUserIds: willContinue.map((vote) => vote.userId), + continuingUserIds, }; }