From 8b779b9d547fd9ddbc09258978e9f8951471755b Mon Sep 17 00:00:00 2001 From: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com> Date: Tue, 4 Nov 2025 14:55:42 -0800 Subject: [PATCH] Fix multiple choice polls to use unique voters as denominator --- ts/components/conversation/TimelineMessage.dom.stories.tsx | 5 +++++ .../conversation/poll-message/PollMessageContents.dom.tsx | 4 ++-- ts/state/selectors/message.preload.ts | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ts/components/conversation/TimelineMessage.dom.stories.tsx b/ts/components/conversation/TimelineMessage.dom.stories.tsx index f1e54f9646..920c81678c 100644 --- a/ts/components/conversation/TimelineMessage.dom.stories.tsx +++ b/ts/components/conversation/TimelineMessage.dom.stories.tsx @@ -2016,6 +2016,7 @@ function createMockPollWithVotes( }) || []; const votesByOption = new Map(); + const uniqueVoterIds = new Set(); let totalNumVotes = 0; resolvedVotes.forEach(vote => { @@ -2024,6 +2025,7 @@ function createMockPollWithVotes( votesByOption.set(index, []); } votesByOption.get(index).push(vote); + uniqueVoterIds.add(vote.from.id); totalNumVotes += 1; }); }); @@ -2034,6 +2036,7 @@ function createMockPollWithVotes( allowMultiple, votesByOption, totalNumVotes, + uniqueVoters: uniqueVoterIds.size, terminatedAt, votes: votes?.map(v => ({ fromConversationId: v.fromId, @@ -2053,6 +2056,7 @@ Poll.args = { allowMultiple: false, votesByOption: new Map(), totalNumVotes: 0, + uniqueVoters: 0, }, status: 'sent', }; @@ -2066,6 +2070,7 @@ PollMultipleChoice.args = { allowMultiple: true, votesByOption: new Map(), totalNumVotes: 0, + uniqueVoters: 0, }, status: 'sent', }; diff --git a/ts/components/conversation/poll-message/PollMessageContents.dom.tsx b/ts/components/conversation/poll-message/PollMessageContents.dom.tsx index a49549667a..0c64a1cc08 100644 --- a/ts/components/conversation/poll-message/PollMessageContents.dom.tsx +++ b/ts/components/conversation/poll-message/PollMessageContents.dom.tsx @@ -100,7 +100,7 @@ export function PollMessageContents({ const [showVotesModal, setShowVotesModal] = useState(false); const isIncoming = direction === 'incoming'; - const totalVotes = poll.totalNumVotes; + const { totalNumVotes: totalVotes, uniqueVoters } = poll; let pollStatusText: string; if (poll.terminatedAt) { @@ -167,7 +167,7 @@ export function PollMessageContents({ const pollVoteEntries = poll.votesByOption.get(index); const optionVotes = pollVoteEntries?.length ?? 0; const percentage = - totalVotes > 0 ? (optionVotes / totalVotes) * 100 : 0; + uniqueVoters > 0 ? (optionVotes / uniqueVoters) * 100 : 0; const weVotedForThis = (pollVoteEntries ?? []).some(v => v.isMe); diff --git a/ts/state/selectors/message.preload.ts b/ts/state/selectors/message.preload.ts index 37ca7987f4..7bceef9886 100644 --- a/ts/state/selectors/message.preload.ts +++ b/ts/state/selectors/message.preload.ts @@ -505,6 +505,7 @@ export type PollVoteWithUserType = { export type PollWithResolvedVotersType = PollMessageAttribute & { votesByOption: Map>; totalNumVotes: number; + uniqueVoters: number; }; const getPollForMessage = ( @@ -527,6 +528,7 @@ const getPollForMessage = ( ...poll, votesByOption: new Map(), totalNumVotes: 0, + uniqueVoters: 0, }; } @@ -573,6 +575,7 @@ const getPollForMessage = ( }); const votesByOption = new Map>(); + const uniqueVoterIds = new Set(); let totalNumVotes = 0; for (const vote of resolvedVotes) { @@ -583,6 +586,7 @@ const getPollForMessage = ( const votes = votesByOption.get(optionIndex); strictAssert(!!votes, 'votes should exist'); votes.push(vote); + uniqueVoterIds.add(vote.from.id); totalNumVotes += 1; } } @@ -591,6 +595,7 @@ const getPollForMessage = ( ...poll, votesByOption, totalNumVotes, + uniqueVoters: uniqueVoterIds.size, }; };