diff --git a/res/css/views/dialogs/_RoomSettingsDialog.pcss b/res/css/views/dialogs/_RoomSettingsDialog.pcss index 143cb6fa3c7..f57f6361932 100644 --- a/res/css/views/dialogs/_RoomSettingsDialog.pcss +++ b/res/css/views/dialogs/_RoomSettingsDialog.pcss @@ -42,6 +42,10 @@ limitations under the License. mask-image: url("$(res)/img/feather-customised/bridge.svg"); } +.mx_RoomSettingsDialog_pollsIcon::before { + mask-image: url("$(res)/img/element-icons/room/composer/poll.svg"); +} + .mx_RoomSettingsDialog_warningIcon::before { mask-image: url("$(res)/img/element-icons/room/settings/advanced.svg"); } diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx index d1ddc62683e..b0527698a83 100644 --- a/src/components/views/dialogs/RoomSettingsDialog.tsx +++ b/src/components/views/dialogs/RoomSettingsDialog.tsx @@ -35,6 +35,7 @@ import { Action } from "../../../dispatcher/actions"; import { VoipRoomSettingsTab } from "../settings/tabs/room/VoipRoomSettingsTab"; import { ActionPayload } from "../../../dispatcher/payloads"; import { NonEmptyArray } from "../../../@types/common"; +import { PollHistoryTab } from "../settings/tabs/room/PollHistoryTab"; export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB"; export const ROOM_VOIP_TAB = "ROOM_VOIP_TAB"; @@ -43,6 +44,7 @@ export const ROOM_ROLES_TAB = "ROOM_ROLES_TAB"; export const ROOM_NOTIFICATIONS_TAB = "ROOM_NOTIFICATIONS_TAB"; export const ROOM_BRIDGES_TAB = "ROOM_BRIDGES_TAB"; export const ROOM_ADVANCED_TAB = "ROOM_ADVANCED_TAB"; +export const ROOM_POLL_HISTORY_TAB = "ROOM_POLL_HISTORY_TAB"; interface IProps { roomId: string; @@ -162,6 +164,17 @@ export default class RoomSettingsDialog extends React.Component ); } + if (SettingsStore.getValue("feature_poll_history")) { + tabs.push( + new Tab( + ROOM_POLL_HISTORY_TAB, + _td("Polls history"), + "mx_RoomSettingsDialog_pollsIcon", + this.props.onFinished(true)} />, + ), + ); + } + if (SettingsStore.getValue(UIFeature.AdvancedSettings)) { tabs.push( new Tab( diff --git a/src/components/views/settings/tabs/room/PollHistoryTab.tsx b/src/components/views/settings/tabs/room/PollHistoryTab.tsx new file mode 100644 index 00000000000..c1866d3b0df --- /dev/null +++ b/src/components/views/settings/tabs/room/PollHistoryTab.tsx @@ -0,0 +1,46 @@ +/* +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, { useContext } from "react"; + +import MatrixClientContext from "../../../../../contexts/MatrixClientContext"; +import { PollHistory } from "../../../polls/pollHistory/PollHistory"; +import { RoomPermalinkCreator } from "../../../../../utils/permalinks/Permalinks"; + +interface IProps { + roomId: string; + onFinished: () => void; +} + +export const PollHistoryTab: React.FC = ({ roomId, onFinished }) => { + const matrixClient = useContext(MatrixClientContext); + const room = matrixClient.getRoom(roomId); + if (!room) { + return null; + } + const permalinkCreator = new RoomPermalinkCreator(room, roomId); + + return ( +
+ +
+ ); +}; diff --git a/test/components/views/dialogs/RoomSettingsDialog-test.tsx b/test/components/views/dialogs/RoomSettingsDialog-test.tsx new file mode 100644 index 00000000000..0e3be2af95c --- /dev/null +++ b/test/components/views/dialogs/RoomSettingsDialog-test.tsx @@ -0,0 +1,111 @@ +/* +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 { fireEvent, render, screen } from "@testing-library/react"; +import { Room, Visibility } from "matrix-js-sdk/src/matrix"; + +import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils"; +import RoomSettingsDialog from "../../../../src/components/views/dialogs/RoomSettingsDialog"; +import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; +import SettingsStore from "../../../../src/settings/SettingsStore"; +import { UIFeature } from "../../../../src/settings/UIFeature"; + +describe("", () => { + const userId = "@alice:server.org"; + const mockClient = getMockClientWithEventEmitter({ + ...mockClientMethodsUser(userId), + isRoomEncrypted: jest.fn().mockReturnValue(false), + getRoom: jest.fn(), + getDomain: jest.fn().mockReturnValue("server.org"), + getLocalAliases: jest.fn().mockResolvedValue({ aliases: [] }), + getRoomDirectoryVisibility: jest.fn().mockResolvedValue({ visibility: Visibility.Private }), + getOrCreateFilter: jest.fn(), + }); + + const roomId = "!room:server.org"; + const room = new Room(roomId, mockClient, userId); + + jest.spyOn(SettingsStore, "getValue"); + + beforeEach(() => { + jest.clearAllMocks(); + + mockClient.getRoom.mockReturnValue(room); + + jest.spyOn(SettingsStore, "getValue").mockReset().mockReturnValue(false); + }); + + const getComponent = (onFinished = jest.fn()) => + render(, { + wrapper: ({ children }) => ( + {children} + ), + }); + + describe("Settings tabs", () => { + it("renders default tabs correctly", () => { + const { container } = getComponent(); + expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot(); + }); + + it("renders voip settings tab when enabled", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (settingName) => settingName === "feature_group_calls", + ); + getComponent(); + expect(screen.getByTestId("settings-tab-ROOM_VOIP_TAB")).toBeInTheDocument(); + }); + + it("renders bridges settings tab when enabled", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (settingName) => settingName === "feature_bridge_state", + ); + getComponent(); + expect(screen.getByTestId("settings-tab-ROOM_BRIDGES_TAB")).toBeInTheDocument(); + }); + + it("renders advanced settings tab when enabled", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (settingName) => settingName === UIFeature.AdvancedSettings, + ); + getComponent(); + expect(screen.getByTestId("settings-tab-ROOM_ADVANCED_TAB")).toBeInTheDocument(); + }); + }); + + describe("poll history", () => { + beforeEach(() => { + jest.spyOn(SettingsStore, "getValue").mockImplementation( + (settingName) => settingName === "feature_poll_history", + ); + + mockClient.getOrCreateFilter.mockResolvedValue("filterId"); + }); + it("renders poll history tab", () => { + getComponent(); + expect(screen.getByTestId("settings-tab-ROOM_POLL_HISTORY_TAB")).toBeInTheDocument(); + }); + + it("displays poll history when tab clicked", () => { + const { container } = getComponent(); + + fireEvent.click(screen.getByText("Polls history")); + + expect(container.querySelector(".mx_SettingsTab")).toMatchSnapshot(); + }); + }); +}); diff --git a/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap b/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap new file mode 100644 index 00000000000..0ddd22f419c --- /dev/null +++ b/test/components/views/dialogs/__snapshots__/RoomSettingsDialog-test.tsx.snap @@ -0,0 +1,129 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` Settings tabs renders default tabs correctly 1`] = ` +NodeList [ +
+ + + General + +
, +
+ + + Security & Privacy + +
, +
+ + + Roles & Permissions + +
, +
+ + + Notifications + +
, +] +`; + +exports[` poll history displays poll history when tab clicked 1`] = ` +
+
+

+ Polls history +

+
+
+ + +
+
+
+
+
+ Loading polls +
+
+
+
+`;