Poll history: detail screen (#10172)
* basic navigation to focused poll * add tooltip * drill permalinkCreator down to poll history * render poll tile and link to timeline * tidy and lint * unit test poll detail * add view poll link to ended pollliste item * strict fix * pr improvements * pass room as prop * permalinkcreator ts assertion
This commit is contained in:
parent
9b2b3ca42e
commit
f57495d3cd
21 changed files with 588 additions and 104 deletions
|
@ -17,6 +17,7 @@
|
||||||
@import "./components/views/beacon/_ShareLatestLocation.pcss";
|
@import "./components/views/beacon/_ShareLatestLocation.pcss";
|
||||||
@import "./components/views/beacon/_StyledLiveBeaconIcon.pcss";
|
@import "./components/views/beacon/_StyledLiveBeaconIcon.pcss";
|
||||||
@import "./components/views/context_menus/_KebabContextMenu.pcss";
|
@import "./components/views/context_menus/_KebabContextMenu.pcss";
|
||||||
|
@import "./components/views/dialogs/polls/_PollDetailHeader.pcss";
|
||||||
@import "./components/views/dialogs/polls/_PollListItem.pcss";
|
@import "./components/views/dialogs/polls/_PollListItem.pcss";
|
||||||
@import "./components/views/dialogs/polls/_PollListItemEnded.pcss";
|
@import "./components/views/dialogs/polls/_PollListItemEnded.pcss";
|
||||||
@import "./components/views/elements/_FilterDropdown.pcss";
|
@import "./components/views/elements/_FilterDropdown.pcss";
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_PollDetailHeader {
|
||||||
|
// override accessiblebutton style
|
||||||
|
font-size: $font-15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_PollDetailHeader_icon {
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
margin-right: $spacing-8;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
|
@ -16,12 +16,17 @@ limitations under the License.
|
||||||
|
|
||||||
.mx_PollListItem {
|
.mx_PollListItem {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_PollListItem_content {
|
||||||
|
width: 100%;
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
grid-gap: $spacing-8;
|
grid-gap: $spacing-8;
|
||||||
grid-template-columns: auto auto auto;
|
grid-template-columns: auto auto auto;
|
||||||
grid-template-rows: auto;
|
grid-template-rows: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
color: $primary-content;
|
color: $primary-content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,14 @@ limitations under the License.
|
||||||
|
|
||||||
.mx_PollListItemEnded {
|
.mx_PollListItemEnded {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_PollListItemEnded_content {
|
||||||
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
color: $primary-content;
|
color: $primary-content;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_PollListItemEnded_title {
|
.mx_PollListItemEnded_title {
|
||||||
|
|
|
@ -262,7 +262,14 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.RoomSummary:
|
case RightPanelPhases.RoomSummary:
|
||||||
card = <RoomSummaryCard room={this.props.room} onClose={this.onClose} />;
|
card = (
|
||||||
|
<RoomSummaryCard
|
||||||
|
room={this.props.room}
|
||||||
|
onClose={this.onClose}
|
||||||
|
// whenever RightPanel is passed a room it is passed a permalinkcreator
|
||||||
|
permalinkCreator={this.props.permalinkCreator!}
|
||||||
|
/>
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.Widget:
|
case RightPanelPhases.Widget:
|
||||||
|
|
89
src/components/views/dialogs/polls/PollDetail.tsx
Normal file
89
src/components/views/dialogs/polls/PollDetail.tsx
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { Poll } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
import { _t } from "../../../../languageHandler";
|
||||||
|
import dispatcher from "../../../../dispatcher/dispatcher";
|
||||||
|
import { Action } from "../../../../dispatcher/actions";
|
||||||
|
import { ViewRoomPayload } from "../../../../dispatcher/payloads/ViewRoomPayload";
|
||||||
|
import { RoomPermalinkCreator } from "../../../../utils/permalinks/Permalinks";
|
||||||
|
import { MediaEventHelper } from "../../../../utils/MediaEventHelper";
|
||||||
|
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";
|
||||||
|
import MPollBody from "../../messages/MPollBody";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
poll: Poll;
|
||||||
|
requestModalClose: () => void;
|
||||||
|
permalinkCreator: RoomPermalinkCreator;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NOOP = (): void => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content of the PollHistoryDialog when a specific poll is selected
|
||||||
|
*/
|
||||||
|
export const PollDetail: React.FC<Props> = ({ poll, permalinkCreator, requestModalClose }) => {
|
||||||
|
// link to end event for ended polls
|
||||||
|
const eventIdToLinkTo = poll.isEnded ? poll.endEventId! : poll.pollId;
|
||||||
|
const linkToTimeline = permalinkCreator.forEvent(eventIdToLinkTo);
|
||||||
|
|
||||||
|
const onLinkClick = (e: ButtonEvent): void => {
|
||||||
|
if ((e as React.MouseEvent).ctrlKey || (e as React.MouseEvent).metaKey) {
|
||||||
|
// native behavior for link on ctrl/cmd + click
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// otherwise handle navigation in the app
|
||||||
|
e.preventDefault();
|
||||||
|
dispatcher.dispatch<ViewRoomPayload>({
|
||||||
|
action: Action.ViewRoom,
|
||||||
|
event_id: eventIdToLinkTo,
|
||||||
|
highlighted: true,
|
||||||
|
room_id: poll.roomId,
|
||||||
|
metricsTrigger: undefined, // room doesn't change
|
||||||
|
});
|
||||||
|
|
||||||
|
requestModalClose();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MPollBody
|
||||||
|
mxEvent={poll.rootEvent}
|
||||||
|
permalinkCreator={permalinkCreator}
|
||||||
|
onHeightChanged={NOOP}
|
||||||
|
onMessageAllowed={NOOP}
|
||||||
|
// MPollBody doesn't use this
|
||||||
|
// and MessageEvent only defines it for eligible events
|
||||||
|
// should be fixed on IBodyProps types
|
||||||
|
// cheat to fulfil the type here
|
||||||
|
mediaEventHelper={{} as unknown as MediaEventHelper}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<AccessibleButton
|
||||||
|
kind="link_inline"
|
||||||
|
element="a"
|
||||||
|
href={linkToTimeline}
|
||||||
|
onClick={onLinkClick}
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
>
|
||||||
|
{_t("View poll in timeline")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
36
src/components/views/dialogs/polls/PollDetailHeader.tsx
Normal file
36
src/components/views/dialogs/polls/PollDetailHeader.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { Icon as LeftCaretIcon } from "../../../../../res/img/element-icons/caret-left.svg";
|
||||||
|
import { _t } from "../../../../languageHandler";
|
||||||
|
import AccessibleButton from "../../elements/AccessibleButton";
|
||||||
|
import { PollHistoryFilter } from "./types";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
filter: PollHistoryFilter;
|
||||||
|
onNavigateBack: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PollDetailHeader: React.FC<Props> = ({ filter, onNavigateBack }) => {
|
||||||
|
return (
|
||||||
|
<AccessibleButton kind="content_inline" onClick={onNavigateBack} className="mx_PollDetailHeader">
|
||||||
|
<LeftCaretIcon className="mx_PollDetailHeader_icon" />
|
||||||
|
{filter === "ACTIVE" ? _t("Active polls") : _t("Past polls")}
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
};
|
|
@ -16,19 +16,23 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { MatrixEvent, Poll } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent, Poll, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { _t } from "../../../../languageHandler";
|
import { _t } from "../../../../languageHandler";
|
||||||
import BaseDialog from "../BaseDialog";
|
import BaseDialog from "../BaseDialog";
|
||||||
import { IDialogProps } from "../IDialogProps";
|
import { IDialogProps } from "../IDialogProps";
|
||||||
import { PollHistoryList } from "./PollHistoryList";
|
import { PollHistoryList } from "./PollHistoryList";
|
||||||
import { PollHistoryFilter } from "./types";
|
import { PollHistoryFilter } from "./types";
|
||||||
|
import { PollDetailHeader } from "./PollDetailHeader";
|
||||||
|
import { PollDetail } from "./PollDetail";
|
||||||
|
import { RoomPermalinkCreator } from "../../../../utils/permalinks/Permalinks";
|
||||||
import { usePollsWithRelations } from "./usePollHistory";
|
import { usePollsWithRelations } from "./usePollHistory";
|
||||||
import { useFetchPastPolls } from "./fetchPastPolls";
|
import { useFetchPastPolls } from "./fetchPastPolls";
|
||||||
|
|
||||||
type PollHistoryDialogProps = Pick<IDialogProps, "onFinished"> & {
|
type PollHistoryDialogProps = Pick<IDialogProps, "onFinished"> & {
|
||||||
roomId: string;
|
room: Room;
|
||||||
matrixClient: MatrixClient;
|
matrixClient: MatrixClient;
|
||||||
|
permalinkCreator: RoomPermalinkCreator;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortEventsByLatest = (left: MatrixEvent, right: MatrixEvent): number => right.getTs() - left.getTs();
|
const sortEventsByLatest = (left: MatrixEvent, right: MatrixEvent): number => right.getTs() - left.getTs();
|
||||||
|
@ -46,25 +50,42 @@ const filterAndSortPolls = (polls: Map<string, Poll>, filter: PollHistoryFilter)
|
||||||
.sort(sortEventsByLatest);
|
.sort(sortEventsByLatest);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PollHistoryDialog: React.FC<PollHistoryDialogProps> = ({ roomId, matrixClient, onFinished }) => {
|
export const PollHistoryDialog: React.FC<PollHistoryDialogProps> = ({
|
||||||
const room = matrixClient.getRoom(roomId)!;
|
room,
|
||||||
const { isLoading } = useFetchPastPolls(room, matrixClient);
|
matrixClient,
|
||||||
const { polls } = usePollsWithRelations(roomId, matrixClient);
|
permalinkCreator,
|
||||||
|
onFinished,
|
||||||
|
}) => {
|
||||||
|
const { polls } = usePollsWithRelations(room.roomId, matrixClient);
|
||||||
const [filter, setFilter] = useState<PollHistoryFilter>("ACTIVE");
|
const [filter, setFilter] = useState<PollHistoryFilter>("ACTIVE");
|
||||||
|
const [focusedPollId, setFocusedPollId] = useState<string | null>(null);
|
||||||
|
const { isLoading } = useFetchPastPolls(room, matrixClient);
|
||||||
|
|
||||||
const pollStartEvents = filterAndSortPolls(polls, filter);
|
const pollStartEvents = filterAndSortPolls(polls, filter);
|
||||||
const isLoadingPollResponses = [...polls.values()].some((poll) => poll.isFetchingResponses);
|
const isLoadingPollResponses = [...polls.values()].some((poll) => poll.isFetchingResponses);
|
||||||
|
|
||||||
|
const focusedPoll = focusedPollId ? polls.get(focusedPollId) : undefined;
|
||||||
|
const title = focusedPoll ? (
|
||||||
|
<PollDetailHeader filter={filter} onNavigateBack={() => setFocusedPollId(null)} />
|
||||||
|
) : (
|
||||||
|
_t("Polls history")
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseDialog title={_t("Polls history")} onFinished={onFinished}>
|
<BaseDialog title={title} onFinished={onFinished}>
|
||||||
<div className="mx_PollHistoryDialog_content">
|
<div className="mx_PollHistoryDialog_content">
|
||||||
|
{focusedPoll ? (
|
||||||
|
<PollDetail poll={focusedPoll} permalinkCreator={permalinkCreator} requestModalClose={onFinished} />
|
||||||
|
) : (
|
||||||
<PollHistoryList
|
<PollHistoryList
|
||||||
pollStartEvents={pollStartEvents}
|
pollStartEvents={pollStartEvents}
|
||||||
isLoading={isLoading || isLoadingPollResponses}
|
isLoading={isLoading || isLoadingPollResponses}
|
||||||
polls={polls}
|
polls={polls}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
onFilterChange={setFilter}
|
onFilterChange={setFilter}
|
||||||
|
onItemClick={setFocusedPollId}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>
|
</BaseDialog>
|
||||||
);
|
);
|
||||||
|
|
|
@ -40,8 +40,9 @@ type PollHistoryListProps = {
|
||||||
pollStartEvents: MatrixEvent[];
|
pollStartEvents: MatrixEvent[];
|
||||||
polls: Map<string, Poll>;
|
polls: Map<string, Poll>;
|
||||||
filter: PollHistoryFilter;
|
filter: PollHistoryFilter;
|
||||||
onFilterChange: (filter: PollHistoryFilter) => void;
|
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
|
onFilterChange: (filter: PollHistoryFilter) => void;
|
||||||
|
onItemClick: (pollId: string) => void;
|
||||||
};
|
};
|
||||||
export const PollHistoryList: React.FC<PollHistoryListProps> = ({
|
export const PollHistoryList: React.FC<PollHistoryListProps> = ({
|
||||||
pollStartEvents,
|
pollStartEvents,
|
||||||
|
@ -49,6 +50,7 @@ export const PollHistoryList: React.FC<PollHistoryListProps> = ({
|
||||||
filter,
|
filter,
|
||||||
isLoading,
|
isLoading,
|
||||||
onFilterChange,
|
onFilterChange,
|
||||||
|
onItemClick,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="mx_PollHistoryList">
|
<div className="mx_PollHistoryList">
|
||||||
|
@ -65,12 +67,17 @@ export const PollHistoryList: React.FC<PollHistoryListProps> = ({
|
||||||
<ol className={classNames("mx_PollHistoryList_list", `mx_PollHistoryList_list_${filter}`)}>
|
<ol className={classNames("mx_PollHistoryList_list", `mx_PollHistoryList_list_${filter}`)}>
|
||||||
{pollStartEvents.map((pollStartEvent) =>
|
{pollStartEvents.map((pollStartEvent) =>
|
||||||
filter === "ACTIVE" ? (
|
filter === "ACTIVE" ? (
|
||||||
<PollListItem key={pollStartEvent.getId()!} event={pollStartEvent} />
|
<PollListItem
|
||||||
|
key={pollStartEvent.getId()!}
|
||||||
|
event={pollStartEvent}
|
||||||
|
onClick={() => onItemClick(pollStartEvent.getId()!)}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PollListItemEnded
|
<PollListItemEnded
|
||||||
key={pollStartEvent.getId()!}
|
key={pollStartEvent.getId()!}
|
||||||
event={pollStartEvent}
|
event={pollStartEvent}
|
||||||
poll={polls.get(pollStartEvent.getId()!)!}
|
poll={polls.get(pollStartEvent.getId()!)!}
|
||||||
|
onClick={() => onItemClick(pollStartEvent.getId()!)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -20,22 +20,30 @@ import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { Icon as PollIcon } from "../../../../../res/img/element-icons/room/composer/poll.svg";
|
import { Icon as PollIcon } from "../../../../../res/img/element-icons/room/composer/poll.svg";
|
||||||
import { formatLocalDateShort } from "../../../../DateUtils";
|
import { formatLocalDateShort } from "../../../../DateUtils";
|
||||||
|
import { _t } from "../../../../languageHandler";
|
||||||
|
import TooltipTarget from "../../elements/TooltipTarget";
|
||||||
|
import { Alignment } from "../../elements/Tooltip";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
event: MatrixEvent;
|
event: MatrixEvent;
|
||||||
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PollListItem: React.FC<Props> = ({ event }) => {
|
export const PollListItem: React.FC<Props> = ({ event, onClick }) => {
|
||||||
const pollEvent = event.unstableExtensibleEvent as unknown as PollStartEvent;
|
const pollEvent = event.unstableExtensibleEvent as unknown as PollStartEvent;
|
||||||
if (!pollEvent) {
|
if (!pollEvent) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const formattedDate = formatLocalDateShort(event.getTs());
|
const formattedDate = formatLocalDateShort(event.getTs());
|
||||||
return (
|
return (
|
||||||
<li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItem">
|
<li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItem" onClick={onClick}>
|
||||||
|
<TooltipTarget label={_t("View poll")} alignment={Alignment.Top}>
|
||||||
|
<div className="mx_PollListItem_content">
|
||||||
<span>{formattedDate}</span>
|
<span>{formattedDate}</span>
|
||||||
<PollIcon className="mx_PollListItem_icon" />
|
<PollIcon className="mx_PollListItem_icon" />
|
||||||
<span className="mx_PollListItem_question">{pollEvent.question.text}</span>
|
<span className="mx_PollListItem_question">{pollEvent.question.text}</span>
|
||||||
|
</div>
|
||||||
|
</TooltipTarget>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,10 +25,13 @@ import { formatLocalDateShort } from "../../../../DateUtils";
|
||||||
import { allVotes, collectUserVotes, countVotes } from "../../messages/MPollBody";
|
import { allVotes, collectUserVotes, countVotes } from "../../messages/MPollBody";
|
||||||
import { PollOption } from "../../polls/PollOption";
|
import { PollOption } from "../../polls/PollOption";
|
||||||
import { Caption } from "../../typography/Caption";
|
import { Caption } from "../../typography/Caption";
|
||||||
|
import TooltipTarget from "../../elements/TooltipTarget";
|
||||||
|
import { Alignment } from "../../elements/Tooltip";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
event: MatrixEvent;
|
event: MatrixEvent;
|
||||||
poll: Poll;
|
poll: Poll;
|
||||||
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type EndedPollState = {
|
type EndedPollState = {
|
||||||
|
@ -88,7 +91,7 @@ const usePollVotes = (poll: Poll): Partial<EndedPollState> => {
|
||||||
* @param event - the poll start MatrixEvent
|
* @param event - the poll start MatrixEvent
|
||||||
* @param poll - Poll instance
|
* @param poll - Poll instance
|
||||||
*/
|
*/
|
||||||
export const PollListItemEnded: React.FC<Props> = ({ event, poll }) => {
|
export const PollListItemEnded: React.FC<Props> = ({ event, poll, onClick }) => {
|
||||||
const pollEvent = poll.pollEvent;
|
const pollEvent = poll.pollEvent;
|
||||||
const { winningAnswers, totalVoteCount } = usePollVotes(poll);
|
const { winningAnswers, totalVoteCount } = usePollVotes(poll);
|
||||||
if (!pollEvent) {
|
if (!pollEvent) {
|
||||||
|
@ -97,7 +100,9 @@ export const PollListItemEnded: React.FC<Props> = ({ event, poll }) => {
|
||||||
const formattedDate = formatLocalDateShort(event.getTs());
|
const formattedDate = formatLocalDateShort(event.getTs());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItemEnded">
|
<li data-testid={`pollListItem-${event.getId()!}`} className="mx_PollListItemEnded" onClick={onClick}>
|
||||||
|
<TooltipTarget label={_t("View poll")} alignment={Alignment.Top}>
|
||||||
|
<div className="mx_PollListItemEnded_content">
|
||||||
<div className="mx_PollListItemEnded_title">
|
<div className="mx_PollListItemEnded_title">
|
||||||
<PollIcon className="mx_PollListItemEnded_icon" />
|
<PollIcon className="mx_PollListItemEnded_icon" />
|
||||||
<span className="mx_PollListItemEnded_question">{pollEvent.question.text}</span>
|
<span className="mx_PollListItemEnded_question">{pollEvent.question.text}</span>
|
||||||
|
@ -122,6 +127,8 @@ export const PollListItemEnded: React.FC<Props> = ({ event, poll }) => {
|
||||||
<div className="mx_PollListItemEnded_voteCount">
|
<div className="mx_PollListItemEnded_voteCount">
|
||||||
<Caption>{_t("Final result based on %(count)s votes", { count: totalVoteCount })}</Caption>
|
<Caption>{_t("Final result based on %(count)s votes", { count: totalVoteCount })}</Caption>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</TooltipTarget>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,6 +37,7 @@ import WidgetAvatar from "../avatars/WidgetAvatar";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import WidgetStore, { IApp } from "../../../stores/WidgetStore";
|
import WidgetStore, { IApp } from "../../../stores/WidgetStore";
|
||||||
import { E2EStatus } from "../../../utils/ShieldUtils";
|
import { E2EStatus } from "../../../utils/ShieldUtils";
|
||||||
|
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||||
import RoomContext from "../../../contexts/RoomContext";
|
import RoomContext from "../../../contexts/RoomContext";
|
||||||
import { UIComponent, UIFeature } from "../../../settings/UIFeature";
|
import { UIComponent, UIFeature } from "../../../settings/UIFeature";
|
||||||
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
|
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
|
||||||
|
@ -55,6 +56,7 @@ import { PollHistoryDialog } from "../dialogs/polls/PollHistoryDialog";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
permalinkCreator: RoomPermalinkCreator;
|
||||||
onClose(): void;
|
onClose(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +270,7 @@ const onRoomSettingsClick = (ev: ButtonEvent): void => {
|
||||||
PosthogTrackers.trackInteraction("WebRightPanelRoomInfoSettingsButton", ev);
|
PosthogTrackers.trackInteraction("WebRightPanelRoomInfoSettingsButton", ev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
|
const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose }) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
const onShareRoomClick = (): void => {
|
const onShareRoomClick = (): void => {
|
||||||
|
@ -285,8 +287,9 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
|
||||||
|
|
||||||
const onRoomPollHistoryClick = (): void => {
|
const onRoomPollHistoryClick = (): void => {
|
||||||
Modal.createDialog(PollHistoryDialog, {
|
Modal.createDialog(PollHistoryDialog, {
|
||||||
roomId: room.roomId,
|
room,
|
||||||
matrixClient: cli,
|
matrixClient: cli,
|
||||||
|
permalinkCreator,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3139,9 +3139,13 @@
|
||||||
"Not a valid Security Key": "Not a valid Security Key",
|
"Not a valid Security Key": "Not a valid Security Key",
|
||||||
"Access your secure message history and set up secure messaging by entering your Security Key.": "Access your secure message history and set up secure messaging by entering your Security Key.",
|
"Access your secure message history and set up secure messaging by entering your Security Key.": "Access your secure message history and set up secure messaging by entering your Security Key.",
|
||||||
"If you've forgotten your Security Key you can <button>set up new recovery options</button>": "If you've forgotten your Security Key you can <button>set up new recovery options</button>",
|
"If you've forgotten your Security Key you can <button>set up new recovery options</button>": "If you've forgotten your Security Key you can <button>set up new recovery options</button>",
|
||||||
|
"View poll in timeline": "View poll in timeline",
|
||||||
|
"Active polls": "Active polls",
|
||||||
|
"Past polls": "Past polls",
|
||||||
"Loading polls": "Loading polls",
|
"Loading polls": "Loading polls",
|
||||||
"There are no active polls in this room": "There are no active polls in this room",
|
"There are no active polls in this room": "There are no active polls in this room",
|
||||||
"There are no past polls in this room": "There are no past polls in this room",
|
"There are no past polls in this room": "There are no past polls in this room",
|
||||||
|
"View poll": "View poll",
|
||||||
"Send custom account data event": "Send custom account data event",
|
"Send custom account data event": "Send custom account data event",
|
||||||
"Send custom room account data event": "Send custom room account data event",
|
"Send custom room account data event": "Send custom room account data event",
|
||||||
"Event Type": "Event Type",
|
"Event Type": "Event Type",
|
||||||
|
|
|
@ -31,6 +31,9 @@ import {
|
||||||
setupRoomWithPollEvents,
|
setupRoomWithPollEvents,
|
||||||
unmockIntlDateTimeFormat,
|
unmockIntlDateTimeFormat,
|
||||||
} from "../../../../test-utils";
|
} from "../../../../test-utils";
|
||||||
|
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks";
|
||||||
|
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
|
||||||
|
import { Action } from "../../../../../src/dispatcher/actions";
|
||||||
|
|
||||||
describe("<PollHistoryDialog />", () => {
|
describe("<PollHistoryDialog />", () => {
|
||||||
// 14.03.2022 16:15
|
// 14.03.2022 16:15
|
||||||
|
@ -57,8 +60,9 @@ describe("<PollHistoryDialog />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
roomId,
|
room,
|
||||||
matrixClient: mockClient,
|
matrixClient: mockClient,
|
||||||
|
permalinkCreator: new RoomPermalinkCreator(room),
|
||||||
onFinished: jest.fn(),
|
onFinished: jest.fn(),
|
||||||
};
|
};
|
||||||
const getComponent = () => render(<PollHistoryDialog {...defaultProps} />);
|
const getComponent = () => render(<PollHistoryDialog {...defaultProps} />);
|
||||||
|
@ -70,9 +74,12 @@ describe("<PollHistoryDialog />", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
room = new Room(roomId, mockClient, userId);
|
room = new Room(roomId, mockClient, userId);
|
||||||
mockClient.getRoom.mockReturnValue(room);
|
mockClient.getRoom.mockReturnValue(room);
|
||||||
|
defaultProps.room = room;
|
||||||
mockClient.relations.mockResolvedValue({ events: [] });
|
mockClient.relations.mockResolvedValue({ events: [] });
|
||||||
const timeline = room.getLiveTimeline();
|
const timeline = room.getLiveTimeline();
|
||||||
jest.spyOn(timeline, "getEvents").mockReturnValue([]);
|
jest.spyOn(timeline, "getEvents").mockReturnValue([]);
|
||||||
|
jest.spyOn(defaultDispatcher, "dispatch").mockClear();
|
||||||
|
defaultProps.onFinished.mockClear();
|
||||||
jest.spyOn(room, "getOrCreateFilteredTimelineSet");
|
jest.spyOn(room, "getOrCreateFilteredTimelineSet");
|
||||||
mockClient.getOrCreateFilter.mockResolvedValue(expectedFilter.filterId!);
|
mockClient.getOrCreateFilter.mockResolvedValue(expectedFilter.filterId!);
|
||||||
mockClient.paginateEventTimeline.mockReset().mockResolvedValue(false);
|
mockClient.paginateEventTimeline.mockReset().mockResolvedValue(false);
|
||||||
|
@ -314,4 +321,165 @@ describe("<PollHistoryDialog />", () => {
|
||||||
// this poll is ended
|
// this poll is ended
|
||||||
expect(getByText("What?")).toBeInTheDocument();
|
expect(getByText("What?")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Poll detail", () => {
|
||||||
|
const timestamp = 1675300825090;
|
||||||
|
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: timestamp, id: "$1" });
|
||||||
|
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: timestamp + 10000, id: "$2" });
|
||||||
|
const pollStart3 = makePollStartEvent("What?", userId, undefined, { ts: timestamp + 70000, id: "$3" });
|
||||||
|
const pollEnd3 = makePollEndEvent(pollStart3.getId()!, roomId, userId, timestamp + 1, "$4");
|
||||||
|
|
||||||
|
it("displays poll detail on active poll list item click", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText, queryByText } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
expect(queryByText("Polls history")).not.toBeInTheDocument();
|
||||||
|
// elements from MPollBody
|
||||||
|
expect(getByText("Question?")).toMatchSnapshot();
|
||||||
|
expect(getByText("Socks")).toBeInTheDocument();
|
||||||
|
expect(getByText("Shoes")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("links to the poll start event from an active poll detail", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
// links to poll start event
|
||||||
|
expect(getByText("View poll in timeline").getAttribute("href")).toBe(
|
||||||
|
`https://matrix.to/#/!room:domain.org/${pollStart1.getId()!}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates in app when clicking view in timeline button", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
const event = new MouseEvent("click", { bubbles: true, cancelable: true });
|
||||||
|
jest.spyOn(event, "preventDefault");
|
||||||
|
fireEvent(getByText("View poll in timeline"), event);
|
||||||
|
|
||||||
|
expect(event.preventDefault).toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
|
||||||
|
action: Action.ViewRoom,
|
||||||
|
event_id: pollStart1.getId()!,
|
||||||
|
highlighted: true,
|
||||||
|
metricsTrigger: undefined,
|
||||||
|
room_id: pollStart1.getRoomId()!,
|
||||||
|
});
|
||||||
|
|
||||||
|
// dialog closed
|
||||||
|
expect(defaultProps.onFinished).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesnt navigate in app when view in timeline link is ctrl + clicked", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
const event = new MouseEvent("click", { bubbles: true, cancelable: true, ctrlKey: true });
|
||||||
|
jest.spyOn(event, "preventDefault");
|
||||||
|
fireEvent(getByText("View poll in timeline"), event);
|
||||||
|
|
||||||
|
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||||
|
expect(defaultDispatcher.dispatch).not.toHaveBeenCalled();
|
||||||
|
expect(defaultProps.onFinished).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates back to poll list from detail view on header click", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText, queryByText, getByTestId, container } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
// detail view
|
||||||
|
expect(getByText("Question?")).toBeInTheDocument();
|
||||||
|
|
||||||
|
// header not shown
|
||||||
|
expect(queryByText("Polls history")).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(getByText("Active polls")).toMatchSnapshot();
|
||||||
|
fireEvent.click(getByText("Active polls"));
|
||||||
|
|
||||||
|
// main list header displayed again
|
||||||
|
expect(getByText("Polls history")).toBeInTheDocument();
|
||||||
|
// active filter still active
|
||||||
|
expect(getByTestId("filter-tab-PollHistoryDialog_filter-ACTIVE").firstElementChild).toBeChecked();
|
||||||
|
// list displayed
|
||||||
|
expect(container.getElementsByClassName("mx_PollHistoryList_list").length).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays poll detail on past poll list item click", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Past polls"));
|
||||||
|
|
||||||
|
// pollStart3 is ended
|
||||||
|
fireEvent.click(getByText("What?"));
|
||||||
|
|
||||||
|
expect(getByText("What?")).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("links to the poll end events from a ended poll detail", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Past polls"));
|
||||||
|
|
||||||
|
// pollStart3 is ended
|
||||||
|
fireEvent.click(getByText("What?"));
|
||||||
|
|
||||||
|
// links to poll end event
|
||||||
|
expect(getByText("View poll in timeline").getAttribute("href")).toBe(
|
||||||
|
`https://matrix.to/#/!room:domain.org/${pollEnd3.getId()!}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates back to poll list from detail view on header click", async () => {
|
||||||
|
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||||
|
|
||||||
|
const { getByText, queryByText, getByTestId, container } = getComponent();
|
||||||
|
await flushPromises();
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
// detail view
|
||||||
|
expect(getByText("Question?")).toBeInTheDocument();
|
||||||
|
|
||||||
|
// header not shown
|
||||||
|
expect(queryByText("Polls history")).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(getByText("Active polls")).toMatchSnapshot();
|
||||||
|
fireEvent.click(getByText("Active polls"));
|
||||||
|
|
||||||
|
// main list header displayed again
|
||||||
|
expect(getByText("Polls history")).toBeInTheDocument();
|
||||||
|
// active filter still active
|
||||||
|
expect(getByTestId("filter-tab-PollHistoryDialog_filter-ACTIVE").firstElementChild).toBeChecked();
|
||||||
|
// list displayed
|
||||||
|
expect(container.getElementsByClassName("mx_PollHistoryList_list").length).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { render } from "@testing-library/react";
|
import { fireEvent, render } from "@testing-library/react";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { PollListItem } from "../../../../../src/components/views/dialogs/polls/PollListItem";
|
import { PollListItem } from "../../../../../src/components/views/dialogs/polls/PollListItem";
|
||||||
|
@ -24,7 +24,7 @@ import { makePollStartEvent, mockIntlDateTimeFormat, unmockIntlDateTimeFormat }
|
||||||
describe("<PollListItem />", () => {
|
describe("<PollListItem />", () => {
|
||||||
const event = makePollStartEvent("Question?", "@me:domain.org");
|
const event = makePollStartEvent("Question?", "@me:domain.org");
|
||||||
event.getContent().origin;
|
event.getContent().origin;
|
||||||
const defaultProps = { event };
|
const defaultProps = { event, onClick: jest.fn() };
|
||||||
const getComponent = (props = {}) => render(<PollListItem {...defaultProps} {...props} />);
|
const getComponent = (props = {}) => render(<PollListItem {...defaultProps} {...props} />);
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
@ -50,4 +50,13 @@ describe("<PollListItem />", () => {
|
||||||
const { container } = getComponent({ event });
|
const { container } = getComponent({ event });
|
||||||
expect(container.firstElementChild).toBeFalsy();
|
expect(container.firstElementChild).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("calls onClick handler on click", () => {
|
||||||
|
const onClick = jest.fn();
|
||||||
|
const { getByText } = getComponent({ onClick });
|
||||||
|
|
||||||
|
fireEvent.click(getByText("Question?"));
|
||||||
|
|
||||||
|
expect(onClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,7 +60,8 @@ describe("<PollListItemEnded />", () => {
|
||||||
});
|
});
|
||||||
const pollEndEvent = makePollEndEvent(pollId, roomId, userId, timestamp + 60000);
|
const pollEndEvent = makePollEndEvent(pollId, roomId, userId, timestamp + 60000);
|
||||||
|
|
||||||
const getComponent = (props: { event: MatrixEvent; poll: Poll }) => render(<PollListItemEnded {...props} />);
|
const getComponent = (props: { event: MatrixEvent; poll: Poll }) =>
|
||||||
|
render(<PollListItemEnded {...props} onClick={jest.fn()} />);
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
// mock default locale to en-GB and set timezone
|
// mock default locale to en-GB and set timezone
|
||||||
|
|
|
@ -1,5 +1,47 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`<PollHistoryDialog /> Poll detail displays poll detail on active poll list item click 1`] = `
|
||||||
|
<h2
|
||||||
|
data-testid="pollQuestion"
|
||||||
|
>
|
||||||
|
Question?
|
||||||
|
</h2>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<PollHistoryDialog /> Poll detail displays poll detail on past poll list item click 1`] = `
|
||||||
|
<h2
|
||||||
|
data-testid="pollQuestion"
|
||||||
|
>
|
||||||
|
What?
|
||||||
|
</h2>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<PollHistoryDialog /> Poll detail navigates back to poll list from detail view on header click 1`] = `
|
||||||
|
<div
|
||||||
|
class="mx_AccessibleButton mx_PollDetailHeader mx_AccessibleButton_hasKind mx_AccessibleButton_kind_content_inline"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_PollDetailHeader_icon"
|
||||||
|
/>
|
||||||
|
Active polls
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`<PollHistoryDialog /> Poll detail navigates back to poll list from detail view on header click 2`] = `
|
||||||
|
<div
|
||||||
|
class="mx_AccessibleButton mx_PollDetailHeader mx_AccessibleButton_hasKind mx_AccessibleButton_kind_content_inline"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_PollDetailHeader_icon"
|
||||||
|
/>
|
||||||
|
Active polls
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`<PollHistoryDialog /> renders a list of active polls when there are polls in the room 1`] = `
|
exports[`<PollHistoryDialog /> renders a list of active polls when there are polls in the room 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
|
@ -70,6 +112,12 @@ exports[`<PollHistoryDialog /> renders a list of active polls when there are pol
|
||||||
<li
|
<li
|
||||||
class="mx_PollListItem"
|
class="mx_PollListItem"
|
||||||
data-testid="pollListItem-$2"
|
data-testid="pollListItem-$2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_PollListItem_content"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
02/02/23
|
02/02/23
|
||||||
|
@ -82,10 +130,18 @@ exports[`<PollHistoryDialog /> renders a list of active polls when there are pol
|
||||||
>
|
>
|
||||||
Where?
|
Where?
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
class="mx_PollListItem"
|
class="mx_PollListItem"
|
||||||
data-testid="pollListItem-$1"
|
data-testid="pollListItem-$1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_PollListItem_content"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
02/02/23
|
02/02/23
|
||||||
|
@ -98,6 +154,8 @@ exports[`<PollHistoryDialog /> renders a list of active polls when there are pol
|
||||||
>
|
>
|
||||||
Question?
|
Question?
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,12 @@ exports[`<PollListItem /> renders a poll 1`] = `
|
||||||
<li
|
<li
|
||||||
class="mx_PollListItem"
|
class="mx_PollListItem"
|
||||||
data-testid="pollListItem-$mypoll"
|
data-testid="pollListItem-$mypoll"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_PollListItem_content"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
01/01/70
|
01/01/70
|
||||||
|
@ -17,6 +23,8 @@ exports[`<PollListItem /> renders a poll 1`] = `
|
||||||
>
|
>
|
||||||
Question?
|
Question?
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -5,6 +5,12 @@ exports[`<PollListItemEnded /> renders a poll with no responses 1`] = `
|
||||||
<li
|
<li
|
||||||
class="mx_PollListItemEnded"
|
class="mx_PollListItemEnded"
|
||||||
data-testid="pollListItem-1"
|
data-testid="pollListItem-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mx_PollListItemEnded_content"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="mx_PollListItemEnded_title"
|
class="mx_PollListItemEnded_title"
|
||||||
|
@ -32,6 +38,8 @@ exports[`<PollListItemEnded /> renders a poll with no responses 1`] = `
|
||||||
Final result based on 0 votes
|
Final result based on 0 votes
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import RightPanelStore from "../../../../src/stores/right-panel/RightPanelStore"
|
||||||
import { RightPanelPhases } from "../../../../src/stores/right-panel/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../../../src/stores/right-panel/RightPanelStorePhases";
|
||||||
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils";
|
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils";
|
||||||
import { PollHistoryDialog } from "../../../../src/components/views/dialogs/polls/PollHistoryDialog";
|
import { PollHistoryDialog } from "../../../../src/components/views/dialogs/polls/PollHistoryDialog";
|
||||||
|
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
|
||||||
|
|
||||||
describe("<RoomSummaryCard />", () => {
|
describe("<RoomSummaryCard />", () => {
|
||||||
const userId = "@alice:domain.org";
|
const userId = "@alice:domain.org";
|
||||||
|
@ -54,6 +55,7 @@ describe("<RoomSummaryCard />", () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
room,
|
room,
|
||||||
onClose: jest.fn(),
|
onClose: jest.fn(),
|
||||||
|
permalinkCreator: new RoomPermalinkCreator(room),
|
||||||
};
|
};
|
||||||
const getComponent = (props = {}) =>
|
const getComponent = (props = {}) =>
|
||||||
render(<RoomSummaryCard {...defaultProps} {...props} />, {
|
render(<RoomSummaryCard {...defaultProps} {...props} />, {
|
||||||
|
@ -145,7 +147,11 @@ describe("<RoomSummaryCard />", () => {
|
||||||
|
|
||||||
fireEvent.click(getByText("Polls history"));
|
fireEvent.click(getByText("Polls history"));
|
||||||
|
|
||||||
expect(modalSpy).toHaveBeenCalledWith(PollHistoryDialog, { roomId, matrixClient: mockClient });
|
expect(modalSpy).toHaveBeenCalledWith(PollHistoryDialog, {
|
||||||
|
room,
|
||||||
|
matrixClient: mockClient,
|
||||||
|
permalinkCreator: defaultProps.permalinkCreator,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,15 @@ export const makePollStartEvent = (
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const makePollEndEvent = (pollStartEventId: string, roomId: string, sender: string, ts = 0): MatrixEvent => {
|
export const makePollEndEvent = (
|
||||||
|
pollStartEventId: string,
|
||||||
|
roomId: string,
|
||||||
|
sender: string,
|
||||||
|
ts = 0,
|
||||||
|
id?: string,
|
||||||
|
): MatrixEvent => {
|
||||||
return new MatrixEvent({
|
return new MatrixEvent({
|
||||||
event_id: uuid4(),
|
event_id: id || uuid4(),
|
||||||
room_id: roomId,
|
room_id: roomId,
|
||||||
origin_server_ts: ts,
|
origin_server_ts: ts,
|
||||||
type: M_POLL_END.name,
|
type: M_POLL_END.name,
|
||||||
|
|
Loading…
Reference in a new issue