Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 6746ce2

Browse files
authored
Fix start DM via right panel (#10278)
1 parent 8d9fdc3 commit 6746ce2

File tree

2 files changed

+46
-29
lines changed

2 files changed

+46
-29
lines changed

src/components/views/right_panel/UserInfo.tsx

+21-11
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,17 @@ export const getE2EStatus = (cli: MatrixClient, userId: string, devices: IDevice
121121
return anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified;
122122
};
123123

124-
async function openDMForUser(matrixClient: MatrixClient, user: RoomMember): Promise<void> {
125-
const startDMUser = new DirectoryMember({
124+
/**
125+
* Converts the member to a DirectoryMember and starts a DM with them.
126+
*/
127+
async function openDmForUser(matrixClient: MatrixClient, user: Member): Promise<void> {
128+
const avatarUrl = user instanceof User ? user.avatarUrl : user.getMxcAvatarUrl();
129+
const startDmUser = new DirectoryMember({
126130
user_id: user.userId,
127131
display_name: user.rawDisplayName,
128-
avatar_url: user.getMxcAvatarUrl(),
132+
avatar_url: avatarUrl,
129133
});
130-
startDmOnFirstMessage(matrixClient, [startDMUser]);
134+
startDmOnFirstMessage(matrixClient, [startDmUser]);
131135
}
132136

133137
type SetUpdating = (updating: boolean) => void;
@@ -310,7 +314,7 @@ function DevicesSection({
310314
);
311315
}
312316

313-
const MessageButton = ({ member }: { member: RoomMember }): JSX.Element => {
317+
const MessageButton = ({ member }: { member: Member }): JSX.Element => {
314318
const cli = useContext(MatrixClientContext);
315319
const [busy, setBusy] = useState(false);
316320

@@ -320,7 +324,7 @@ const MessageButton = ({ member }: { member: RoomMember }): JSX.Element => {
320324
onClick={async () => {
321325
if (busy) return;
322326
setBusy(true);
323-
await openDMForUser(cli, member);
327+
await openDmForUser(cli, member);
324328
setBusy(false);
325329
}}
326330
className="mx_UserInfo_field"
@@ -332,7 +336,7 @@ const MessageButton = ({ member }: { member: RoomMember }): JSX.Element => {
332336
};
333337

334338
export const UserOptionsSection: React.FC<{
335-
member: RoomMember;
339+
member: Member;
336340
isIgnored: boolean;
337341
canInvite: boolean;
338342
isSpace?: boolean;
@@ -360,8 +364,9 @@ export const UserOptionsSection: React.FC<{
360364
}, [cli, member]);
361365

362366
const ignore = useCallback(async () => {
367+
const name = (member instanceof User ? member.displayName : member.name) || member.userId;
363368
const { finished } = Modal.createDialog(QuestionDialog, {
364-
title: _t("Ignore %(user)s", { user: member.name }),
369+
title: _t("Ignore %(user)s", { user: name }),
365370
description: (
366371
<div>
367372
{_t(
@@ -394,7 +399,7 @@ export const UserOptionsSection: React.FC<{
394399
</AccessibleButton>
395400
);
396401

397-
if (member.roomId && !isSpace) {
402+
if (member instanceof RoomMember && member.roomId && !isSpace) {
398403
const onReadReceiptButton = function (): void {
399404
const room = cli.getRoom(member.roomId);
400405
dis.dispatch<ViewRoomPayload>({
@@ -415,7 +420,7 @@ export const UserOptionsSection: React.FC<{
415420
});
416421
};
417422

418-
const room = cli.getRoom(member.roomId);
423+
const room = member instanceof RoomMember ? cli.getRoom(member.roomId) : undefined;
419424
if (room?.getEventReadUpTo(member.userId)) {
420425
readReceiptButton = (
421426
<AccessibleButton kind="link" onClick={onReadReceiptButton} className="mx_UserInfo_field">
@@ -431,7 +436,12 @@ export const UserOptionsSection: React.FC<{
431436
);
432437
}
433438

434-
if (canInvite && (member?.membership ?? "leave") === "leave" && shouldShowComponent(UIComponent.InviteUsers)) {
439+
if (
440+
member instanceof RoomMember &&
441+
canInvite &&
442+
(member?.membership ?? "leave") === "leave" &&
443+
shouldShowComponent(UIComponent.InviteUsers)
444+
) {
435445
const roomId = member && member.roomId ? member.roomId : SdkContextClass.instance.roomViewStore.getRoomId();
436446
const onInviteUserButton = async (ev: ButtonEvent): Promise<void> => {
437447
try {

test/components/views/right_panel/UserInfo-test.tsx

+25-18
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ import MultiInviter from "../../../../src/utils/MultiInviter";
4343
import * as mockVerification from "../../../../src/verification";
4444
import Modal from "../../../../src/Modal";
4545
import { E2EStatus } from "../../../../src/utils/ShieldUtils";
46+
import { DirectoryMember, startDmOnFirstMessage } from "../../../../src/utils/direct-messages";
47+
48+
jest.mock("../../../../src/utils/direct-messages", () => ({
49+
...jest.requireActual("../../../../src/utils/direct-messages"),
50+
startDmOnFirstMessage: jest.fn(),
51+
}));
4652

4753
jest.mock("../../../../src/dispatcher/dispatcher");
4854

@@ -121,7 +127,7 @@ const mockClient = mocked({
121127
setPowerLevel: jest.fn(),
122128
} as unknown as MatrixClient);
123129

124-
const defaultUserId = "@test:test";
130+
const defaultUserId = "@user:example.com";
125131
const defaultUser = new User(defaultUserId);
126132

127133
beforeEach(() => {
@@ -550,23 +556,6 @@ describe("<UserOptionsSection />", () => {
550556
});
551557
});
552558

553-
it("calling .invite with a null roomId still calls .invite and shows default error message", async () => {
554-
inviteSpy.mockRejectedValue({ this: "could be anything" });
555-
556-
// render the component and click the button
557-
renderComponent({ canInvite: true, member: { ...member, roomId: null } });
558-
const inviteButton = screen.getByRole("button", { name: /invite/i });
559-
expect(inviteButton).toBeInTheDocument();
560-
await userEvent.click(inviteButton);
561-
562-
expect(inviteSpy).toHaveBeenCalledTimes(1);
563-
564-
// check that the default test error message is displayed
565-
await waitFor(() => {
566-
expect(screen.getByText(/operation failed/i)).toBeInTheDocument();
567-
});
568-
});
569-
570559
it("shows a modal before ignoring the user", async () => {
571560
const originalCreateDialog = Modal.createDialog;
572561
const modalSpy = (Modal.createDialog = jest.fn().mockReturnValue({
@@ -612,6 +601,24 @@ describe("<UserOptionsSection />", () => {
612601
await userEvent.click(screen.getByRole("button", { name: "Unignore" }));
613602
expect(mockClient.setIgnoredUsers).toHaveBeenCalledWith([]);
614603
});
604+
605+
it.each([
606+
["for a RoomMember", member, member.getMxcAvatarUrl()],
607+
["for a User", defaultUser, defaultUser.avatarUrl],
608+
])(
609+
"clicking »message« %s should start a DM",
610+
async (test: string, member: RoomMember | User, expectedAvatarUrl: string | undefined) => {
611+
renderComponent({ member });
612+
await userEvent.click(screen.getByText("Message"));
613+
expect(startDmOnFirstMessage).toHaveBeenCalledWith(mockClient, [
614+
new DirectoryMember({
615+
user_id: member.userId,
616+
display_name: member.rawDisplayName,
617+
avatar_url: expectedAvatarUrl,
618+
}),
619+
]);
620+
},
621+
);
615622
});
616623

617624
describe("<PowerLevelEditor />", () => {

0 commit comments

Comments
 (0)