diff --git a/src/hooks/room/useRoomCall.ts b/src/hooks/room/useRoomCall.ts
index 852804aa9d6..aed7fcbff43 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 dfe361c17c5..594d9a8d802 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) => {