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

Commit 99be435

Browse files
author
Charly Nguyen
committed
Apply PR feedback
Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>
1 parent 4bc1c8c commit 99be435

File tree

2 files changed

+75
-31
lines changed

2 files changed

+75
-31
lines changed

src/components/views/rooms/RoomKnocksBar.tsx

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,41 +30,48 @@ import AccessibleButton from "../elements/AccessibleButton";
3030
import Heading from "../typography/Heading";
3131

3232
export const RoomKnocksBar: VFC<{ room: Room }> = ({ room }) => {
33+
const [disabled, setDisabled] = useState(false);
34+
const knockMembers = useTypedEventEmitterState(
35+
room,
36+
RoomStateEvent.Members,
37+
useCallback(() => room.getMembersWithMembership("knock"), [room]),
38+
);
39+
const knockMembersCount = knockMembers.length;
40+
41+
if (room.getJoinRule() !== JoinRule.Knock || knockMembersCount === 0) return null;
42+
3343
const client = room.client;
3444
const userId = client.getUserId() || "";
3545
const canInvite = room.canInvite(userId);
3646
const member = room.getMember(userId);
3747
const state = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
3848
const canKick = member && state ? state.hasSufficientPowerLevelFor("kick", member.powerLevel) : false;
3949

50+
if (!canInvite && !canKick) return null;
51+
52+
const onError = (error: MatrixError): void => {
53+
Modal.createDialog(ErrorDialog, { title: error.name, description: error.message });
54+
};
55+
4056
const handleApprove = (userId: string): void => {
4157
setDisabled(true);
42-
client.invite(room.roomId, userId).catch(onError);
58+
client
59+
.invite(room.roomId, userId)
60+
.catch(onError)
61+
.finally(() => setDisabled(false));
4362
};
4463

4564
const handleDeny = (userId: string): void => {
4665
setDisabled(true);
47-
client.kick(room.roomId, userId).catch(onError);
66+
client
67+
.kick(room.roomId, userId)
68+
.catch(onError)
69+
.finally(() => setDisabled(false));
4870
};
4971

5072
const handleOpenRoomSettings = (): void =>
5173
dis.dispatch({ action: "open_room_settings", room_id: room.roomId, initial_tab_id: RoomSettingsTab.People });
5274

53-
const onError = (error: MatrixError): void => {
54-
setDisabled(false);
55-
Modal.createDialog(ErrorDialog, { title: error.name, description: error.message });
56-
};
57-
58-
const [disabled, setDisabled] = useState(false);
59-
const knockMembers = useTypedEventEmitterState(
60-
room,
61-
RoomStateEvent.Members,
62-
useCallback(() => room.getMembersWithMembership("knock"), [room]),
63-
);
64-
const knockMembersCount = knockMembers.length;
65-
66-
if (room.getJoinRule() !== JoinRule.Knock || knockMembersCount === 0 || (!canInvite && !canKick)) return null;
67-
6875
let buttons: ReactElement = (
6976
<AccessibleButton
7077
className="mx_RoomKnocksBar_action"
@@ -89,7 +96,7 @@ export const RoomKnocksBar: VFC<{ room: Room }> = ({ room }) => {
8996
disabled={!canKick || disabled}
9097
kind="icon_primary_outline"
9198
onClick={() => handleDeny(knockMembers[0].userId)}
92-
title={_t("Deny")}
99+
title={_t("action|deny")}
93100
>
94101
<XIcon width={18} height={18} />
95102
</AccessibleButton>
@@ -98,7 +105,7 @@ export const RoomKnocksBar: VFC<{ room: Room }> = ({ room }) => {
98105
disabled={!canInvite || disabled}
99106
kind="icon_primary"
100107
onClick={() => handleApprove(knockMembers[0].userId)}
101-
title={_t("Approve")}
108+
title={_t("action|approve")}
102109
>
103110
<CheckIcon width={18} height={18} />
104111
</AccessibleButton>

test/components/views/rooms/RoomKnocksBar-test.tsx

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ describe("RoomKnocksBar", () => {
5252
const room = new Room(roomId, client, userId);
5353
const state = room.getLiveTimeline().getState(EventTimeline.FORWARDS)!;
5454

55-
const getButton = (name: "Approve" | "Deny" | "View" | "View message") => screen.getByRole("button", { name });
55+
type ButtonNames = "Approve" | "Deny" | "View" | "View message";
56+
const getButton = (name: ButtonNames) => screen.getByRole("button", { name });
5657
const getComponent = (room: Room) =>
5758
render(
5859
<MatrixClientContext.Provider value={client}>
@@ -134,16 +135,33 @@ describe("RoomKnocksBar", () => {
134135
expect(getComponent(room).container.firstChild).toBeNull();
135136
});
136137

138+
it("unhides the bar when a new knock request appears", () => {
139+
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([]);
140+
const { container } = getComponent(room);
141+
expect(container.firstChild).toBeNull();
142+
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([bob]);
143+
act(() => {
144+
room.emit(RoomStateEvent.Members, new MatrixEvent(), state, bob);
145+
});
146+
expect(container.firstChild).not.toBeNull();
147+
});
148+
149+
it("updates when the list of knocking users changes", () => {
150+
getComponent(room);
151+
expect(screen.getByRole("heading")).toHaveTextContent("Asking to join");
152+
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([bob, jane]);
153+
act(() => {
154+
room.emit(RoomStateEvent.Members, new MatrixEvent(), state, jane);
155+
});
156+
expect(screen.getByRole("heading")).toHaveTextContent("2 people asking to join");
157+
});
158+
137159
describe("when knock members count is 1", () => {
138160
beforeEach(() => jest.spyOn(room, "getMembersWithMembership").mockReturnValue([bob]));
139161

140-
it("renders a heading", () => {
162+
it("renders a heading and a paragraph with name and user ID", () => {
141163
getComponent(room);
142164
expect(screen.getByRole("heading")).toHaveTextContent("Asking to join");
143-
});
144-
145-
it("renders a paragraph", () => {
146-
getComponent(room);
147165
expect(screen.getByRole("paragraph")).toHaveTextContent(`${bob.name} (${bob.userId})`);
148166
});
149167

@@ -157,20 +175,38 @@ describe("RoomKnocksBar", () => {
157175
});
158176
});
159177

178+
type TestCase = [string, ButtonNames, () => void];
179+
it.each<TestCase>([
180+
["deny request fails", "Deny", () => jest.spyOn(client, "kick").mockRejectedValue(error)],
181+
["deny request succeeds", "Deny", () => jest.spyOn(client, "kick").mockResolvedValue({})],
182+
["approve request fails", "Approve", () => jest.spyOn(client, "invite").mockRejectedValue(error)],
183+
["approve request succeeds", "Approve", () => jest.spyOn(client, "invite").mockResolvedValue({})],
184+
])("toggles the disabled attribute for the buttons when a %s", async (_, buttonName, setup) => {
185+
setup();
186+
getComponent(room);
187+
fireEvent.click(getButton(buttonName));
188+
expect(getButton("Deny")).toHaveAttribute("disabled");
189+
expect(getButton("Approve")).toHaveAttribute("disabled");
190+
await act(() => flushPromises());
191+
expect(getButton("Deny")).not.toHaveAttribute("disabled");
192+
expect(getButton("Approve")).not.toHaveAttribute("disabled");
193+
});
194+
160195
it("disables the deny button if the power level is insufficient", () => {
161196
jest.spyOn(state, "hasSufficientPowerLevelFor").mockReturnValue(false);
162197
getComponent(room);
163198
expect(getButton("Deny")).toHaveAttribute("disabled");
164199
});
165200

166-
it("calls kick on deny", () => {
201+
it("calls kick on deny", async () => {
167202
jest.spyOn(client, "kick").mockResolvedValue({});
168203
getComponent(room);
169204
fireEvent.click(getButton("Deny"));
205+
await act(() => flushPromises());
170206
expect(client.kick).toHaveBeenCalledWith(roomId, bob.userId);
171207
});
172208

173-
it("fails to deny a request", async () => {
209+
it("displays an error when a deny request fails", async () => {
174210
jest.spyOn(client, "kick").mockRejectedValue(error);
175211
getComponent(room);
176212
fireEvent.click(getButton("Deny"));
@@ -187,14 +223,15 @@ describe("RoomKnocksBar", () => {
187223
expect(getButton("Approve")).toHaveAttribute("disabled");
188224
});
189225

190-
it("calls invite on approve", () => {
226+
it("calls invite on approve", async () => {
191227
jest.spyOn(client, "invite").mockResolvedValue({});
192228
getComponent(room);
193229
fireEvent.click(getButton("Approve"));
194-
expect(client.kick).toHaveBeenCalledWith(roomId, bob.userId);
230+
await act(() => flushPromises());
231+
expect(client.invite).toHaveBeenCalledWith(roomId, bob.userId);
195232
});
196233

197-
it("fails to approve a request", async () => {
234+
it("displays an error when an approval fails", async () => {
198235
jest.spyOn(client, "invite").mockRejectedValue(error);
199236
getComponent(room);
200237
fireEvent.click(getButton("Approve"));
@@ -205,7 +242,7 @@ describe("RoomKnocksBar", () => {
205242
});
206243
});
207244

208-
it("succeeds to deny/approve a request", () => {
245+
it("hides the bar when someone else approves or denies the waiting person", () => {
209246
getComponent(room);
210247
jest.spyOn(room, "getMembersWithMembership").mockReturnValue([]);
211248
act(() => {

0 commit comments

Comments
 (0)