From a70fcfd0bcf7f8c85986da18001ea11597989a7c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 24 Jul 2023 10:12:37 +0100 Subject: [PATCH] Fix invite dialog showing the same user multiple times (#11308) * Fix invite dialog showing the same user multiple times * Add test * Improve coverage --- src/components/views/dialogs/InviteDialog.tsx | 11 +++++-- .../views/dialogs/InviteDialog-test.tsx | 31 ++++++++++++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 7bb714c025..fa81a28bee 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -21,6 +21,7 @@ import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixCall } from "matrix-js-sdk/src/webrtc/call"; import { logger } from "matrix-js-sdk/src/logger"; import { MatrixError } from "matrix-js-sdk/src/matrix"; +import { uniqBy } from "lodash"; import { Icon as InfoIcon } from "../../../../res/img/element-icons/info.svg"; import { Icon as EmailPillAvatarIcon } from "../../../../res/img/icon-email-pill-avatar.svg"; @@ -384,6 +385,7 @@ export default class InviteDialog extends React.PureComponent t); // cheap clone for mutation - const idx = targets.indexOf(member); + const idx = targets.findIndex((m) => m.userId === member.userId); if (idx >= 0) { targets.splice(idx, 1); } else { @@ -945,11 +949,11 @@ export default class InviteDialog extends React.PureComponent t.userId), }); } else { this.setState({ - targets: [...this.state.targets, ...toAdd], + targets: uniqBy([...this.state.targets, ...toAdd], (t) => t.userId), }); } }; @@ -1001,6 +1005,7 @@ export default class InviteDialog extends React.PureComponent { return ( + !this.state.recents.some((m) => m.userId === u.userId) && !sourceMembers.some((m) => m.userId === u.userId) && !priorityAdditionalMembers.some((m) => m.userId === u.userId) && !otherAdditionalMembers.some((m) => m.userId === u.userId) diff --git a/test/components/views/dialogs/InviteDialog-test.tsx b/test/components/views/dialogs/InviteDialog-test.tsx index fdd936a421..645492cd3d 100644 --- a/test/components/views/dialogs/InviteDialog-test.tsx +++ b/test/components/views/dialogs/InviteDialog-test.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { fireEvent, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { RoomType } from "matrix-js-sdk/src/@types/event"; import { MatrixClient, MatrixError, Room } from "matrix-js-sdk/src/matrix"; @@ -366,6 +366,35 @@ describe("InviteDialog", () => { ]); }); + it("should not allow pasting the same user multiple times", async () => { + render(); + + const input = screen.getByTestId("invite-dialog-input"); + input.focus(); + await userEvent.paste(`${bobId}`); + await userEvent.paste(`${bobId}`); + await userEvent.paste(`${bobId}`); + + expect(input).toHaveValue(""); + await expect(screen.findAllByText(bobId, { selector: "a" })).resolves.toHaveLength(1); + }); + + it("should add to selection on click of user tile", async () => { + render(); + + const input = screen.getByTestId("invite-dialog-input"); + input.focus(); + await userEvent.keyboard(`${aliceId}`); + + const btn = await screen.findByText(aliceId, { + selector: ".mx_InviteDialog_tile_nameStack_userId .mx_InviteDialog_tile--room_highlight", + }); + fireEvent.click(btn); + + const tile = await screen.findByText(aliceId, { selector: ".mx_InviteDialog_userTile_name" }); + expect(tile).toBeInTheDocument(); + }); + describe("when inviting a user with an unknown profile", () => { beforeEach(async () => { render();