diff --git a/src/hooks/room/useRoomCall.ts b/src/hooks/room/useRoomCall.ts index 852804aa9d..aed7fcbff4 100644 --- a/src/hooks/room/useRoomCall.ts +++ b/src/hooks/room/useRoomCall.ts @@ -189,6 +189,8 @@ export const useRoomCall = ( // We only want to prompt to pin the widget if it's not element call based. const isECWidget = WidgetType.CALL.matches(widget?.type ?? ""); const promptPinWidget = !isECWidget && canPinWidget && !widgetPinned; + const userId = room.client.getUserId(); + const canInviteToRoom = userId ? room.canInvite(userId) : false; const state = useMemo((): State => { if (activeCalls.find((call) => call.roomId != room.roomId)) { return State.Ongoing; @@ -199,8 +201,9 @@ export const useRoomCall = ( if (hasLegacyCall) { return State.Ongoing; } - - if (memberCount <= 1) { + const canCallAlone = + canInviteToRoom && (room.getJoinRule() === "public" || room.getJoinRule() === JoinRule.Knock); + if (!(memberCount > 1 || canCallAlone)) { return State.NoOneHere; } @@ -210,6 +213,7 @@ export const useRoomCall = ( return State.NoCall; }, [ activeCalls, + canInviteToRoom, hasGroupCall, hasJitsiWidget, hasLegacyCall, @@ -218,7 +222,7 @@ export const useRoomCall = ( mayEditWidgets, memberCount, promptPinWidget, - room.roomId, + room, ]); const voiceCallClick = useCallback( diff --git a/test/components/views/rooms/RoomHeader-test.tsx b/test/components/views/rooms/RoomHeader-test.tsx index dfe361c17c..594d9a8d80 100644 --- a/test/components/views/rooms/RoomHeader-test.tsx +++ b/test/components/views/rooms/RoomHeader-test.tsx @@ -33,6 +33,7 @@ import { getByLabelText, getByRole, getByText, + queryAllByLabelText, render, RenderOptions, screen, @@ -83,7 +84,6 @@ describe("RoomHeader", () => { ); let room: Room; - const ROOM_ID = "!1:example.org"; let setCardSpy: jest.SpyInstance | undefined; @@ -371,7 +371,7 @@ describe("RoomHeader", () => { } }); - it("can't call if you have no friends", () => { + it("can't call if you have no friends and cannot invite friends", () => { mockRoomMembers(room, 1); const { container } = render(, getWrapper()); for (const button of getAllByLabelText(container, "There's no one here to call")) { @@ -379,6 +379,29 @@ describe("RoomHeader", () => { } }); + it("can call if you have no friends but can invite friends", () => { + mockRoomMembers(room, 1); + // go through all the different `canInvite` and `getJoinRule` combinations + jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite); + jest.spyOn(room, "canInvite").mockReturnValue(false); + const { container: containerNoInviteNotPublic } = render(, getWrapper()); + expect(queryAllByLabelText(containerNoInviteNotPublic, "There's no one here to call")).toHaveLength(2); + jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock); + jest.spyOn(room, "canInvite").mockReturnValue(false); + const { container: containerNoInvitePublic } = render(, getWrapper()); + expect(queryAllByLabelText(containerNoInvitePublic, "There's no one here to call")).toHaveLength(2); + + jest.spyOn(room, "canInvite").mockReturnValue(true); + jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Invite); + const { container: containerInviteNotPublic } = render(, getWrapper()); + expect(queryAllByLabelText(containerInviteNotPublic, "There's no one here to call")).toHaveLength(2); + + jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock); + jest.spyOn(room, "canInvite").mockReturnValue(true); + const { container: containerInvitePublic } = render(, getWrapper()); + expect(queryAllByLabelText(containerInvitePublic, "There's no one here to call")).toHaveLength(0); + }); + it("calls using legacy or jitsi", async () => { mockRoomMembers(room, 2); jest.spyOn(room.currentState, "mayClientSendStateEvent").mockImplementation((key) => {