Poll: Support date in vote (#6760)
This commit is contained in:
parent
aa44302ed4
commit
ac06cb6e80
@ -12,7 +12,10 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
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-size: 0.9375rem;
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
@ -38,7 +41,6 @@
|
|||||||
.poll-voters {
|
.poll-voters {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 3rem;
|
min-height: 3rem;
|
||||||
padding: 0 0.75rem;
|
|
||||||
|
|
||||||
.Spinner {
|
.Spinner {
|
||||||
--spinner-size: 1.25rem;
|
--spinner-size: 1.25rem;
|
||||||
@ -50,6 +52,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chat-item-clickable {
|
.chat-item-clickable {
|
||||||
|
.ListItem-button {
|
||||||
|
padding-inline-start: 1rem;
|
||||||
|
padding-inline-end: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.ChatInfo .Avatar.size-tiny {
|
.ChatInfo .Avatar.size-tiny {
|
||||||
margin-right: 1.75rem;
|
margin-right: 1.75rem;
|
||||||
}
|
}
|
||||||
@ -60,6 +67,11 @@
|
|||||||
margin-left: 1.75rem;
|
margin-left: 1.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vote-date {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ShowMoreButton {
|
.ShowMoreButton {
|
||||||
|
|||||||
@ -11,8 +11,10 @@ import type {
|
|||||||
ApiPollAnswer,
|
ApiPollAnswer,
|
||||||
ApiPollResult,
|
ApiPollResult,
|
||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
|
import type { PollVote } from '../../global/types/tabState';
|
||||||
|
|
||||||
import { selectTabState } from '../../global/selectors';
|
import { selectTabState } from '../../global/selectors';
|
||||||
|
import { formatMediaDateTime } from '../../util/dates/dateFormat';
|
||||||
import { isUserId } from '../../util/entities/ids';
|
import { isUserId } from '../../util/entities/ids';
|
||||||
import { renderTextWithEntities } from '../common/helpers/renderTextWithEntities';
|
import { renderTextWithEntities } from '../common/helpers/renderTextWithEntities';
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
voters?: string[];
|
votes?: PollVote[];
|
||||||
offset: string;
|
offset: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,7 +51,7 @@ const PollAnswerResults: FC<OwnProps & StateProps> = ({
|
|||||||
answer,
|
answer,
|
||||||
answerVote,
|
answerVote,
|
||||||
totalVoters,
|
totalVoters,
|
||||||
voters,
|
votes,
|
||||||
offset,
|
offset,
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
@ -60,7 +62,7 @@ const PollAnswerResults: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const prevVotersCount = usePreviousDeprecated<number>(answerVote.votersCount);
|
const prevVotersCount = usePreviousDeprecated<number>(answerVote.votersCount);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
const areVotersLoaded = Boolean(voters);
|
const areVotersLoaded = Boolean(votes);
|
||||||
const { option, text } = answer;
|
const { option, text } = answer;
|
||||||
const lang = useOldLang();
|
const lang = useOldLang();
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ const PollAnswerResults: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, [voters]);
|
}, [votes]);
|
||||||
|
|
||||||
const handleMemberClick = useCallback((id: string) => {
|
const handleMemberClick = useCallback((id: string) => {
|
||||||
openChat({ id });
|
openChat({ id });
|
||||||
@ -91,7 +93,7 @@ const PollAnswerResults: FC<OwnProps & StateProps> = ({
|
|||||||
}, [closePollResults, openChat]);
|
}, [closePollResults, openChat]);
|
||||||
|
|
||||||
function renderViewMoreButton() {
|
function renderViewMoreButton() {
|
||||||
const leftVotersCount = answerVote.votersCount - voters!.length;
|
const leftVotersCount = answerVote.votersCount - votes!.length;
|
||||||
|
|
||||||
return answerVote.votersCount > INITIAL_LIMIT && leftVotersCount > 0 && (
|
return answerVote.votersCount > INITIAL_LIMIT && leftVotersCount > 0 && (
|
||||||
<ShowMoreButton
|
<ShowMoreButton
|
||||||
@ -106,32 +108,34 @@ const PollAnswerResults: FC<OwnProps & StateProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="PollAnswerResults">
|
<div className="PollAnswerResults">
|
||||||
<div className="poll-voters">
|
<div className="poll-voters">
|
||||||
{voters
|
{votes
|
||||||
? voters.map((id) => (
|
? votes.map(({ peerId, date }) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={id}
|
key={peerId}
|
||||||
className="chat-item-clickable"
|
className="chat-item-clickable"
|
||||||
|
onClick={() => handleMemberClick(peerId)}
|
||||||
onClick={() => handleMemberClick(id)}
|
|
||||||
>
|
>
|
||||||
{isUserId(id) ? (
|
{isUserId(peerId) ? (
|
||||||
<PrivateChatInfo
|
<PrivateChatInfo
|
||||||
avatarSize="tiny"
|
avatarSize="tiny"
|
||||||
userId={id}
|
userId={peerId}
|
||||||
forceShowSelf
|
forceShowSelf
|
||||||
noStatusOrTyping
|
noStatusOrTyping
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<GroupChatInfo
|
<GroupChatInfo
|
||||||
avatarSize="tiny"
|
avatarSize="tiny"
|
||||||
chatId={id}
|
chatId={peerId}
|
||||||
noStatusOrTyping
|
noStatusOrTyping
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<span className="vote-date">
|
||||||
|
{formatMediaDateTime(lang, date * 1000, true)}
|
||||||
|
</span>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))
|
))
|
||||||
: <Loading />}
|
: <Loading />}
|
||||||
{voters && renderViewMoreButton()}
|
{votes && renderViewMoreButton()}
|
||||||
</div>
|
</div>
|
||||||
<div className="answer-head" dir={lang.isRtl ? 'rtl' : undefined}>
|
<div className="answer-head" dir={lang.isRtl ? 'rtl' : undefined}>
|
||||||
<span className="answer-title" dir="auto">
|
<span className="answer-title" dir="auto">
|
||||||
@ -155,10 +159,10 @@ function getPercentage(value: number, total: number) {
|
|||||||
|
|
||||||
export default memo(withGlobal<OwnProps>(
|
export default memo(withGlobal<OwnProps>(
|
||||||
(global, { answer }: OwnProps): Complete<StateProps> => {
|
(global, { answer }: OwnProps): Complete<StateProps> => {
|
||||||
const { voters, offsets } = selectTabState(global).pollResults;
|
const { votesByOption, offsets } = selectTabState(global).pollResults;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
voters: voters?.[answer.option],
|
votes: votesByOption?.[answer.option],
|
||||||
offset: (offsets?.[answer.option]) || '',
|
offset: (offsets?.[answer.option]) || '',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -52,6 +52,7 @@ import {
|
|||||||
partition,
|
partition,
|
||||||
split,
|
split,
|
||||||
unique,
|
unique,
|
||||||
|
uniqueByField,
|
||||||
} from '../../../util/iteratees';
|
} from '../../../util/iteratees';
|
||||||
import { getMessageKey, isLocalMessageId } from '../../../util/keys/messageKey';
|
import { getMessageKey, isLocalMessageId } from '../../../util/keys/messageKey';
|
||||||
import { getTranslationFn, type RegularLangFnParameters } from '../../../util/localization';
|
import { getTranslationFn, type RegularLangFnParameters } from '../../../util/localization';
|
||||||
@ -1477,17 +1478,17 @@ addActionHandler('loadPollOptionResults', async (global, actions, payload): Prom
|
|||||||
|
|
||||||
const tabState = selectTabState(global, tabId);
|
const tabState = selectTabState(global, tabId);
|
||||||
const { pollResults } = tabState;
|
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, {
|
global = updateTabState(global, {
|
||||||
pollResults: {
|
pollResults: {
|
||||||
...pollResults,
|
...pollResults,
|
||||||
voters: {
|
votesByOption: {
|
||||||
...voters,
|
...votesByOption,
|
||||||
[option]: unique([
|
[option]: newVotes,
|
||||||
...(!shouldResetVoters && voters?.[option] ? voters[option] : []),
|
|
||||||
...result.votes.map((vote) => vote.peerId),
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
offsets: {
|
offsets: {
|
||||||
...(pollResults.offsets ? pollResults.offsets : {}),
|
...(pollResults.offsets ? pollResults.offsets : {}),
|
||||||
|
|||||||
@ -297,7 +297,7 @@ addActionHandler('openPollResults', (global, actions, payload): ActionReturnType
|
|||||||
pollResults: {
|
pollResults: {
|
||||||
chatId,
|
chatId,
|
||||||
messageId,
|
messageId,
|
||||||
voters: {},
|
votesByOption: {},
|
||||||
},
|
},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
setGlobal(global);
|
setGlobal(global);
|
||||||
@ -307,7 +307,7 @@ addActionHandler('openPollResults', (global, actions, payload): ActionReturnType
|
|||||||
pollResults: {
|
pollResults: {
|
||||||
chatId,
|
chatId,
|
||||||
messageId,
|
messageId,
|
||||||
voters: {},
|
votesByOption: {},
|
||||||
},
|
},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,6 +102,11 @@ import type { RegularLangFnParameters } from '../../util/localization';
|
|||||||
import type { ProfileCollectionKey } from '../selectors/payments';
|
import type { ProfileCollectionKey } from '../selectors/payments';
|
||||||
import type { CallbackAction } from './actions';
|
import type { CallbackAction } from './actions';
|
||||||
|
|
||||||
|
export type PollVote = {
|
||||||
|
peerId: string;
|
||||||
|
date: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type TabState = {
|
export type TabState = {
|
||||||
id: number;
|
id: number;
|
||||||
isBlurred?: boolean;
|
isBlurred?: boolean;
|
||||||
@ -418,7 +423,7 @@ export type TabState = {
|
|||||||
pollResults: {
|
pollResults: {
|
||||||
chatId?: string;
|
chatId?: string;
|
||||||
messageId?: number;
|
messageId?: number;
|
||||||
voters?: Record<string, string[]>; // TODO Rename to `voterIds`
|
votesByOption?: Record<string, PollVote[]>;
|
||||||
offsets?: Record<string, string>;
|
offsets?: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user