From 43c67ce4bf6a51ca9b19c81b05747d66e21b49c3 Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 31 Jan 2023 04:42:18 -0500 Subject: [PATCH] Add ignore user confirmation dialog (#6116) Signed-off-by: Robin Townsend --- src/components/views/right_panel/UserInfo.tsx | 43 ++++++++++----- src/i18n/strings/en_EN.json | 2 + .../views/right_panel/UserInfo-test.tsx | 53 +++++++++++++++++++ 3 files changed, 85 insertions(+), 13 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 0a742c61cc..72df34290d 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -353,25 +353,42 @@ export const UserOptionsSection: React.FC<{ }); }; + const unignore = useCallback(() => { + const ignoredUsers = cli.getIgnoredUsers(); + const index = ignoredUsers.indexOf(member.userId); + if (index !== -1) ignoredUsers.splice(index, 1); + cli.setIgnoredUsers(ignoredUsers); + }, [cli, member]); + + const ignore = useCallback(async () => { + const { finished } = Modal.createDialog(QuestionDialog, { + title: _t("Ignore %(user)s", { user: member.name }), + description: ( +
+ {_t( + "All messages and invites from this user will be hidden. " + + "Are you sure you want to ignore them?", + )} +
+ ), + button: _t("Ignore"), + }); + const [confirmed] = await finished; + + if (confirmed) { + const ignoredUsers = cli.getIgnoredUsers(); + ignoredUsers.push(member.userId); + cli.setIgnoredUsers(ignoredUsers); + } + }, [cli, member]); + // Only allow the user to ignore the user if its not ourselves // same goes for jumping to read receipt if (!isMe) { - const onIgnoreToggle = (): void => { - const ignoredUsers = cli.getIgnoredUsers(); - if (isIgnored) { - const index = ignoredUsers.indexOf(member.userId); - if (index !== -1) ignoredUsers.splice(index, 1); - } else { - ignoredUsers.push(member.userId); - } - - cli.setIgnoredUsers(ignoredUsers); - }; - ignoreButton = ( {isIgnored ? _t("Unignore") : _t("Ignore")} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6d315bf38d..0edce777e7 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2235,6 +2235,8 @@ "%(count)s sessions|one": "%(count)s session", "Hide sessions": "Hide sessions", "Message": "Message", + "Ignore %(user)s": "Ignore %(user)s", + "All messages and invites from this user will be hidden. Are you sure you want to ignore them?": "All messages and invites from this user will be hidden. Are you sure you want to ignore them?", "Jump to read receipt": "Jump to read receipt", "Mention": "Mention", "Share Link to User": "Share Link to User", diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 49a5b134bc..049fa6ef28 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -72,6 +72,7 @@ const mockRoom = mocked({ getMxcAvatarUrl: jest.fn().mockReturnValue("mock-avatar-url"), name: "test room", on: jest.fn(), + off: jest.fn(), currentState: { getStateEvents: jest.fn(), on: jest.fn(), @@ -83,9 +84,12 @@ const mockClient = mocked({ getUser: jest.fn(), isGuest: jest.fn().mockReturnValue(false), isUserIgnored: jest.fn(), + getIgnoredUsers: jest.fn(), + setIgnoredUsers: jest.fn(), isCryptoEnabled: jest.fn(), getUserId: jest.fn(), on: jest.fn(), + off: jest.fn(), isSynapseAdministrator: jest.fn().mockResolvedValue(false), isRoomEncrypted: jest.fn().mockReturnValue(false), doesServerSupportUnstableFeature: jest.fn().mockReturnValue(false), @@ -386,8 +390,11 @@ describe("", () => { beforeEach(() => { inviteSpy.mockReset(); + mockClient.setIgnoredUsers.mockClear(); }); + afterEach(() => Modal.closeCurrentModal("End of test")); + afterAll(() => { inviteSpy.mockRestore(); }); @@ -543,6 +550,52 @@ describe("", () => { expect(screen.getByText(/operation failed/i)).toBeInTheDocument(); }); }); + + it("shows a modal before ignoring the user", async () => { + const originalCreateDialog = Modal.createDialog; + const modalSpy = (Modal.createDialog = jest.fn().mockReturnValue({ + finished: Promise.resolve([true]), + close: () => {}, + })); + + try { + mockClient.getIgnoredUsers.mockReturnValue([]); + renderComponent({ isIgnored: false }); + + await userEvent.click(screen.getByRole("button", { name: "Ignore" })); + expect(modalSpy).toHaveBeenCalled(); + expect(mockClient.setIgnoredUsers).toHaveBeenLastCalledWith([member.userId]); + } finally { + Modal.createDialog = originalCreateDialog; + } + }); + + it("cancels ignoring the user", async () => { + const originalCreateDialog = Modal.createDialog; + const modalSpy = (Modal.createDialog = jest.fn().mockReturnValue({ + finished: Promise.resolve([false]), + close: () => {}, + })); + + try { + mockClient.getIgnoredUsers.mockReturnValue([]); + renderComponent({ isIgnored: false }); + + await userEvent.click(screen.getByRole("button", { name: "Ignore" })); + expect(modalSpy).toHaveBeenCalled(); + expect(mockClient.setIgnoredUsers).not.toHaveBeenCalled(); + } finally { + Modal.createDialog = originalCreateDialog; + } + }); + + it("unignores the user", async () => { + mockClient.getIgnoredUsers.mockReturnValue([member.userId]); + renderComponent({ isIgnored: true }); + + await userEvent.click(screen.getByRole("button", { name: "Unignore" })); + expect(mockClient.setIgnoredUsers).toHaveBeenCalledWith([]); + }); }); describe("", () => {