mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-24 02:18:15 +01:00
Add ability for poll author to terminate a poll
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { tw } from '../../../axo/tw.dom.js';
|
||||
import { AxoButton } from '../../../axo/AxoButton.dom.js';
|
||||
import { Modal } from '../../Modal.dom.js';
|
||||
import { Avatar, AvatarSize } from '../../Avatar.dom.js';
|
||||
import { ContactName } from '../ContactName.dom.js';
|
||||
@@ -16,12 +17,18 @@ type PollVotesModalProps = {
|
||||
i18n: LocalizerType;
|
||||
poll: PollWithResolvedVotersType;
|
||||
onClose: () => void;
|
||||
endPoll: (messageId: string) => void;
|
||||
canEndPoll?: boolean;
|
||||
messageId: string;
|
||||
};
|
||||
|
||||
export function PollVotesModal({
|
||||
i18n,
|
||||
poll,
|
||||
onClose,
|
||||
endPoll,
|
||||
canEndPoll,
|
||||
messageId,
|
||||
}: PollVotesModalProps): JSX.Element {
|
||||
return (
|
||||
<Modal
|
||||
@@ -41,56 +48,64 @@ export function PollVotesModal({
|
||||
<div className={tw('type-body-large')}>{poll.question}</div>
|
||||
</div>
|
||||
|
||||
{poll.options.map((option, index) => {
|
||||
{poll.options.map((option, index, array) => {
|
||||
const voters = poll.votesByOption.get(index) || [];
|
||||
const optionKey = `option-${index}`;
|
||||
const isLastOption = index === array.length - 1;
|
||||
|
||||
return (
|
||||
<div key={optionKey} className={tw('flex flex-col')}>
|
||||
{/* Option Header */}
|
||||
<div
|
||||
className={tw('mb-3 flex items-start gap-3 text-label-primary')}
|
||||
>
|
||||
<div className={tw('type-title-small')}>{option}</div>
|
||||
<React.Fragment key={optionKey}>
|
||||
<div className={tw('flex flex-col')}>
|
||||
{/* Option Header */}
|
||||
<div
|
||||
className={tw('ms-auto mt-[2px] shrink-0 type-body-medium')}
|
||||
className={tw(
|
||||
'mb-3 flex items-start gap-3 text-label-primary'
|
||||
)}
|
||||
>
|
||||
{i18n('icu:PollVotesModal__voteCount', {
|
||||
count: voters.length,
|
||||
})}
|
||||
<div className={tw('type-title-small')}>{option}</div>
|
||||
<div
|
||||
className={tw('ms-auto mt-[2px] shrink-0 type-body-medium')}
|
||||
>
|
||||
{i18n('icu:PollVotesModal__voteCount', {
|
||||
count: voters.length,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Voters List */}
|
||||
<div className={tw('flex flex-col gap-4')}>
|
||||
{voters.map((vote: PollVoteWithUserType) => (
|
||||
<div
|
||||
key={vote.from.id}
|
||||
className={tw('flex items-center gap-3')}
|
||||
>
|
||||
<Avatar
|
||||
avatarUrl={vote.from.avatarUrl}
|
||||
badge={undefined}
|
||||
color={vote.from.color}
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
noteToSelf={false}
|
||||
phoneNumber={vote.from.phoneNumber}
|
||||
profileName={vote.from.profileName}
|
||||
sharedGroupNames={vote.from.sharedGroupNames}
|
||||
size={AvatarSize.THIRTY_SIX}
|
||||
title={vote.from.title}
|
||||
/>
|
||||
<div className={tw('min-w-0 flex-1')}>
|
||||
<ContactName
|
||||
title={vote.from.title}
|
||||
module={tw('type-body-large text-label-primary')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Voters List */}
|
||||
<div className={tw('flex flex-col gap-4')}>
|
||||
{voters.map((vote: PollVoteWithUserType) => (
|
||||
<div
|
||||
key={vote.from.id}
|
||||
className={tw('flex items-center gap-3')}
|
||||
>
|
||||
<Avatar
|
||||
avatarUrl={vote.from.avatarUrl}
|
||||
badge={undefined}
|
||||
color={vote.from.color}
|
||||
conversationType="direct"
|
||||
i18n={i18n}
|
||||
noteToSelf={false}
|
||||
phoneNumber={vote.from.phoneNumber}
|
||||
profileName={vote.from.profileName}
|
||||
sharedGroupNames={vote.from.sharedGroupNames}
|
||||
size={AvatarSize.THIRTY_SIX}
|
||||
title={vote.from.title}
|
||||
/>
|
||||
<div className={tw('min-w-0 flex-1')}>
|
||||
<ContactName
|
||||
title={vote.from.title}
|
||||
module={tw('type-body-large text-label-primary')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{!isLastOption && (
|
||||
<hr className={tw('border-t-[0.5px] border-label-secondary')} />
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -104,6 +119,24 @@ export function PollVotesModal({
|
||||
{i18n('icu:PollVotesModal__noVotes')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!poll.terminatedAt && canEndPoll && (
|
||||
<>
|
||||
<hr className={tw('border-t-[0.5px] border-label-secondary')} />
|
||||
<div className={tw('flex justify-center')}>
|
||||
<AxoButton.Root
|
||||
size="lg"
|
||||
variant="secondary"
|
||||
onClick={() => {
|
||||
endPoll(messageId);
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
{i18n('icu:Poll__end-poll')}
|
||||
</AxoButton.Root>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user