From 0194db52a355f65610a0253c65f8fa13e7f436ee Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Sat, 29 May 2021 00:14:46 -0400 Subject: [PATCH 1/4] Add ignore user confirmation dialog Signed-off-by: Robin Townsend --- src/components/views/right_panel/UserInfo.tsx | 29 ++++++++++++++----- src/i18n/strings/en_EN.json | 2 ++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 6e56b9259b2..ef8784fdd8e 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -334,21 +334,34 @@ const UserOptionsSection: React.FC<{ // Only allow the user to ignore the user if its not ourselves // same goes for jumping to read receipt if (!isMe) { - const onIgnoreToggle = () => { + const unignore = () => { const ignoredUsers = cli.getIgnoredUsers(); - if (isIgnored) { - const index = ignoredUsers.indexOf(member.userId); - if (index !== -1) ignoredUsers.splice(index, 1); - } else { + const index = ignoredUsers.indexOf(member.userId); + if (index !== -1) ignoredUsers.splice(index, 1); + cli.setIgnoredUsers(ignoredUsers); + }; + + const ignore = async () => { + const { finished } = Modal.createTrackedDialog('Ignore User', '', 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.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 3d6fcb86438..6da10f014df 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1744,6 +1744,8 @@ "%(count)s sessions|other": "%(count)s sessions", "%(count)s sessions|one": "%(count)s session", "Hide sessions": "Hide sessions", + "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", "Invite": "Invite", From b19c8a09305d12f1eef2aab415cc8c1b08708791 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 30 Jan 2023 11:56:13 -0500 Subject: [PATCH 2/4] Format with Prettier --- src/components/views/right_panel/UserInfo.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 31bb9fce144..72df34290d8 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -363,10 +363,14 @@ export const UserOptionsSection: React.FC<{ 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?") } -
, + 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; From d7cb7caed9e899a3dbc5b0f10587ec9125449223 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 30 Jan 2023 12:47:23 -0500 Subject: [PATCH 3/4] Add tests --- .../views/right_panel/UserInfo-test.tsx | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 49a5b134bc9..38d0328af03 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -83,6 +83,8 @@ 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(), @@ -383,13 +385,17 @@ describe("", () => { }; const inviteSpy = jest.spyOn(MultiInviter.prototype, "invite"); + const modalSpy = jest.spyOn(Modal, "createDialog"); - beforeEach(() => { + afterEach(() => { inviteSpy.mockReset(); + modalSpy.mockReset(); + mockClient.setIgnoredUsers.mockClear(); }); afterAll(() => { inviteSpy.mockRestore(); + modalSpy.mockRestore(); }); it("always shows share user button", () => { @@ -543,6 +549,40 @@ describe("", () => { expect(screen.getByText(/operation failed/i)).toBeInTheDocument(); }); }); + + it("shows a modal before ignoring the user", async () => { + mockClient.getIgnoredUsers.mockReturnValue([]); + modalSpy.mockReturnValue({ + finished: Promise.resolve([true]), + close: () => {}, + }); + renderComponent({ isIgnored: false }); + + await userEvent.click(screen.getByRole("button", { name: "Ignore" })); + expect(modalSpy).toHaveBeenCalled(); + expect(mockClient.setIgnoredUsers).toHaveBeenLastCalledWith([member.userId]); + }); + + it("cancels ignoring the user", async () => { + mockClient.getIgnoredUsers.mockReturnValue([]); + modalSpy.mockReturnValue({ + finished: Promise.resolve([false]), + close: () => {}, + }); + renderComponent({ isIgnored: false }); + + await userEvent.click(screen.getByRole("button", { name: "Ignore" })); + expect(modalSpy).toHaveBeenCalled(); + expect(mockClient.setIgnoredUsers).not.toHaveBeenCalled(); + }); + + 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("", () => { From 0518b502350fe29114c1c19edfd5a639d50a0fd3 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 30 Jan 2023 16:25:50 -0500 Subject: [PATCH 4/4] Fix tests --- .../views/right_panel/UserInfo-test.tsx | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 38d0328af03..049fa6ef281 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(), @@ -88,6 +89,7 @@ const mockClient = mocked({ 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), @@ -385,17 +387,16 @@ describe("", () => { }; const inviteSpy = jest.spyOn(MultiInviter.prototype, "invite"); - const modalSpy = jest.spyOn(Modal, "createDialog"); - afterEach(() => { + beforeEach(() => { inviteSpy.mockReset(); - modalSpy.mockReset(); mockClient.setIgnoredUsers.mockClear(); }); + afterEach(() => Modal.closeCurrentModal("End of test")); + afterAll(() => { inviteSpy.mockRestore(); - modalSpy.mockRestore(); }); it("always shows share user button", () => { @@ -551,29 +552,41 @@ describe("", () => { }); it("shows a modal before ignoring the user", async () => { - mockClient.getIgnoredUsers.mockReturnValue([]); - modalSpy.mockReturnValue({ + const originalCreateDialog = Modal.createDialog; + const modalSpy = (Modal.createDialog = jest.fn().mockReturnValue({ finished: Promise.resolve([true]), close: () => {}, - }); - renderComponent({ isIgnored: false }); - - await userEvent.click(screen.getByRole("button", { name: "Ignore" })); - expect(modalSpy).toHaveBeenCalled(); - expect(mockClient.setIgnoredUsers).toHaveBeenLastCalledWith([member.userId]); + })); + + 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 () => { - mockClient.getIgnoredUsers.mockReturnValue([]); - modalSpy.mockReturnValue({ + const originalCreateDialog = Modal.createDialog; + const modalSpy = (Modal.createDialog = jest.fn().mockReturnValue({ finished: Promise.resolve([false]), close: () => {}, - }); - renderComponent({ isIgnored: false }); - - await userEvent.click(screen.getByRole("button", { name: "Ignore" })); - expect(modalSpy).toHaveBeenCalled(); - expect(mockClient.setIgnoredUsers).not.toHaveBeenCalled(); + })); + + 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 () => {