From ac06cb6e8061f2c4d4e9d5ed2a2cf695913619b3 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Tue, 31 Mar 2026 11:28:46 +0200 Subject: [PATCH] Poll: Support date in vote (#6760) --- src/components/right/PollAnswerResults.scss | 16 +++++++-- src/components/right/PollAnswerResults.tsx | 36 ++++++++++++--------- src/global/actions/api/messages.ts | 15 +++++---- src/global/actions/ui/messages.ts | 4 +-- src/global/types/tabState.ts | 7 +++- 5 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/components/right/PollAnswerResults.scss b/src/components/right/PollAnswerResults.scss index fc857239c..7863b2d76 100644 --- a/src/components/right/PollAnswerResults.scss +++ b/src/components/right/PollAnswerResults.scss @@ -12,7 +12,10 @@ display: flex; align-items: center; - padding: 1rem 0.75rem 0.5rem 1rem; + padding-top: 1rem; + padding-bottom: 0.5rem; + padding-inline-start: 1rem; + padding-inline-end: 0.75rem; font-size: 0.9375rem; font-weight: var(--font-weight-medium); @@ -38,7 +41,6 @@ .poll-voters { position: relative; min-height: 3rem; - padding: 0 0.75rem; .Spinner { --spinner-size: 1.25rem; @@ -50,6 +52,11 @@ } .chat-item-clickable { + .ListItem-button { + padding-inline-start: 1rem; + padding-inline-end: 0.75rem; + } + .ChatInfo .Avatar.size-tiny { margin-right: 1.75rem; } @@ -60,6 +67,11 @@ margin-left: 1.75rem; } } + + .vote-date { + font-size: 0.875rem; + color: var(--color-text-secondary); + } } .ShowMoreButton { diff --git a/src/components/right/PollAnswerResults.tsx b/src/components/right/PollAnswerResults.tsx index 00647bd9f..aea9cc66e 100644 --- a/src/components/right/PollAnswerResults.tsx +++ b/src/components/right/PollAnswerResults.tsx @@ -11,8 +11,10 @@ import type { ApiPollAnswer, ApiPollResult, } from '../../api/types'; +import type { PollVote } from '../../global/types/tabState'; import { selectTabState } from '../../global/selectors'; +import { formatMediaDateTime } from '../../util/dates/dateFormat'; import { isUserId } from '../../util/entities/ids'; import { renderTextWithEntities } from '../common/helpers/renderTextWithEntities'; @@ -36,7 +38,7 @@ type OwnProps = { }; type StateProps = { - voters?: string[]; + votes?: PollVote[]; offset: string; }; @@ -49,7 +51,7 @@ const PollAnswerResults: FC = ({ answer, answerVote, totalVoters, - voters, + votes, offset, }) => { const { @@ -60,7 +62,7 @@ const PollAnswerResults: FC = ({ const prevVotersCount = usePreviousDeprecated(answerVote.votersCount); const [isLoading, setIsLoading] = useState(true); - const areVotersLoaded = Boolean(voters); + const areVotersLoaded = Boolean(votes); const { option, text } = answer; const lang = useOldLang(); @@ -83,7 +85,7 @@ const PollAnswerResults: FC = ({ useEffect(() => { setIsLoading(false); - }, [voters]); + }, [votes]); const handleMemberClick = useCallback((id: string) => { openChat({ id }); @@ -91,7 +93,7 @@ const PollAnswerResults: FC = ({ }, [closePollResults, openChat]); function renderViewMoreButton() { - const leftVotersCount = answerVote.votersCount - voters!.length; + const leftVotersCount = answerVote.votersCount - votes!.length; return answerVote.votersCount > INITIAL_LIMIT && leftVotersCount > 0 && ( = ({ return (
- {voters - ? voters.map((id) => ( + {votes + ? votes.map(({ peerId, date }) => ( handleMemberClick(id)} + onClick={() => handleMemberClick(peerId)} > - {isUserId(id) ? ( + {isUserId(peerId) ? ( ) : ( )} + + {formatMediaDateTime(lang, date * 1000, true)} + )) : } - {voters && renderViewMoreButton()} + {votes && renderViewMoreButton()}
@@ -155,10 +159,10 @@ function getPercentage(value: number, total: number) { export default memo(withGlobal( (global, { answer }: OwnProps): Complete => { - const { voters, offsets } = selectTabState(global).pollResults; + const { votesByOption, offsets } = selectTabState(global).pollResults; return { - voters: voters?.[answer.option], + votes: votesByOption?.[answer.option], offset: (offsets?.[answer.option]) || '', }; }, diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index d450ecc47..92ea8892d 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -52,6 +52,7 @@ import { partition, split, unique, + uniqueByField, } from '../../../util/iteratees'; import { getMessageKey, isLocalMessageId } from '../../../util/keys/messageKey'; import { getTranslationFn, type RegularLangFnParameters } from '../../../util/localization'; @@ -1477,17 +1478,17 @@ addActionHandler('loadPollOptionResults', async (global, actions, payload): Prom const tabState = selectTabState(global, tabId); const { pollResults } = tabState; - const { voters } = tabState.pollResults; + const { votesByOption } = pollResults; + + const existingVotes = !shouldResetVoters && votesByOption?.[option] ? votesByOption[option] : []; + const newVotes = uniqueByField([...existingVotes, ...result.votes], 'peerId'); global = updateTabState(global, { pollResults: { ...pollResults, - voters: { - ...voters, - [option]: unique([ - ...(!shouldResetVoters && voters?.[option] ? voters[option] : []), - ...result.votes.map((vote) => vote.peerId), - ]), + votesByOption: { + ...votesByOption, + [option]: newVotes, }, offsets: { ...(pollResults.offsets ? pollResults.offsets : {}), diff --git a/src/global/actions/ui/messages.ts b/src/global/actions/ui/messages.ts index 9b4a30185..fa37e5508 100644 --- a/src/global/actions/ui/messages.ts +++ b/src/global/actions/ui/messages.ts @@ -297,7 +297,7 @@ addActionHandler('openPollResults', (global, actions, payload): ActionReturnType pollResults: { chatId, messageId, - voters: {}, + votesByOption: {}, }, }, tabId); setGlobal(global); @@ -307,7 +307,7 @@ addActionHandler('openPollResults', (global, actions, payload): ActionReturnType pollResults: { chatId, messageId, - voters: {}, + votesByOption: {}, }, }, tabId); } diff --git a/src/global/types/tabState.ts b/src/global/types/tabState.ts index 181e63f45..6a70b6507 100644 --- a/src/global/types/tabState.ts +++ b/src/global/types/tabState.ts @@ -102,6 +102,11 @@ import type { RegularLangFnParameters } from '../../util/localization'; import type { ProfileCollectionKey } from '../selectors/payments'; import type { CallbackAction } from './actions'; +export type PollVote = { + peerId: string; + date: number; +}; + export type TabState = { id: number; isBlurred?: boolean; @@ -418,7 +423,7 @@ export type TabState = { pollResults: { chatId?: string; messageId?: number; - voters?: Record; // TODO Rename to `voterIds` + votesByOption?: Record; offsets?: Record; };