diff --git a/src/components/viewmodels/roomlist/RoomListHeaderViewModel.tsx b/src/components/viewmodels/roomlist/RoomListHeaderViewModel.tsx index fb822b8129..9aa63451f3 100644 --- a/src/components/viewmodels/roomlist/RoomListHeaderViewModel.tsx +++ b/src/components/viewmodels/roomlist/RoomListHeaderViewModel.tsx @@ -6,7 +6,7 @@ */ import { useCallback } from "react"; -import { JoinRule, type Room, RoomEvent, RoomType } from "matrix-js-sdk/src/matrix"; +import { EventTimeline, EventType, JoinRule, type Room, RoomEvent, RoomType } from "matrix-js-sdk/src/matrix"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; import { UIComponent } from "../../../settings/UIFeature"; @@ -126,11 +126,19 @@ export interface RoomListHeaderViewState { export function useRoomListHeaderViewModel(): RoomListHeaderViewState { const matrixClient = useMatrixClientContext(); const { activeSpace, title } = useSpace(); + const isSpaceRoom = Boolean(activeSpace); - const canCreateRoom = shouldShowComponent(UIComponent.CreateRooms); + const canCreateRoomInSpace = Boolean( + activeSpace + ?.getLiveTimeline() + .getState(EventTimeline.FORWARDS) + ?.maySendStateEvent(EventType.RoomAvatar, matrixClient.getSafeUserId()), + ); + // If we are in a space, we check canCreateRoomInSpace + const canCreateRoom = shouldShowComponent(UIComponent.CreateRooms) && (!isSpaceRoom || canCreateRoomInSpace); const canCreateVideoRoom = useFeatureEnabled("feature_video_rooms"); - const displayComposeMenu = canCreateRoom; - const displaySpaceMenu = Boolean(activeSpace); + const displayComposeMenu = canCreateRoom || canCreateVideoRoom; + const displaySpaceMenu = isSpaceRoom; const canInviteInSpace = Boolean( activeSpace?.getJoinRule() === JoinRule.Public || activeSpace?.canInvite(matrixClient.getSafeUserId()), ); diff --git a/src/components/views/rooms/RoomListPanel/RoomListHeaderView.tsx b/src/components/views/rooms/RoomListPanel/RoomListHeaderView.tsx index e8cc5dccb3..213d83c605 100644 --- a/src/components/views/rooms/RoomListPanel/RoomListHeaderView.tsx +++ b/src/components/views/rooms/RoomListPanel/RoomListHeaderView.tsx @@ -42,7 +42,14 @@ export function RoomListHeaderView(): JSX.Element {

{vm.title}

{vm.displaySpaceMenu && } - {vm.displayComposeMenu && } + {/* If we don't display the compose menu, it means that the user can only send DM */} + {vm.displayComposeMenu ? ( + + ) : ( + vm.createChatRoom(e.nativeEvent)}> + + + )} ); } diff --git a/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx b/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx index 43b7cb2b7d..2233949d71 100644 --- a/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx +++ b/test/unit-tests/components/viewmodels/roomlist/RoomListHeaderViewModel-test.tsx @@ -6,7 +6,7 @@ */ import { renderHook } from "jest-matrix-react"; -import { JoinRule, type MatrixClient, type Room, RoomType } from "matrix-js-sdk/src/matrix"; +import { JoinRule, type MatrixClient, type Room, type RoomState, RoomType } from "matrix-js-sdk/src/matrix"; import { mocked } from "jest-mock"; import { useRoomListHeaderViewModel } from "../../../../../src/components/viewmodels/roomlist/RoomListHeaderViewModel"; @@ -79,12 +79,39 @@ describe("useRoomListHeaderViewModel", () => { expect(result.current.canCreateRoom).toBe(true); }); + it("should be displayComposeMenu=true if the user can creates video room", () => { + mocked(shouldShowComponent).mockReturnValue(false); + jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); + + const { result } = render(); + expect(result.current.displayComposeMenu).toBe(true); + }); + it("should be displaySpaceMenu=true if the user is in a space", () => { jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); const { result } = render(); expect(result.current.displaySpaceMenu).toBe(true); }); + it("should be canCreateRoom=false if the user has not the right to create a room in a space", () => { + mocked(shouldShowComponent).mockReturnValue(true); + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + + const { result } = render(); + expect(result.current.canCreateRoom).toBe(false); + }); + + it("should be canCreateRoom=true if the user has the right to create a room in a space", () => { + mocked(shouldShowComponent).mockReturnValue(true); + jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); + jest.spyOn(space.getLiveTimeline(), "getState").mockReturnValue({ + maySendStateEvent: jest.fn().mockReturnValue(true), + } as unknown as RoomState); + + const { result } = render(); + expect(result.current.canCreateRoom).toBe(true); + }); + it("should be canInviteInSpace=true if the space join rule is public", () => { jest.spyOn(SpaceStore.instance, "activeSpaceRoom", "get").mockReturnValue(space); jest.spyOn(space, "getJoinRule").mockReturnValue(JoinRule.Public); diff --git a/test/unit-tests/components/views/rooms/RoomListPanel/RoomListHeaderView-test.tsx b/test/unit-tests/components/views/rooms/RoomListPanel/RoomListHeaderView-test.tsx index 3a7e189d91..a2422283c8 100644 --- a/test/unit-tests/components/views/rooms/RoomListPanel/RoomListHeaderView-test.tsx +++ b/test/unit-tests/components/views/rooms/RoomListPanel/RoomListHeaderView-test.tsx @@ -51,12 +51,16 @@ describe("", () => { expect(asFragment()).toMatchSnapshot(); }); - it("should not display the compose menu", () => { + it("should not display the compose menu", async () => { + const user = userEvent.setup(); mocked(useRoomListHeaderViewModel).mockReturnValue({ ...defaultValue, displayComposeMenu: false }); const { asFragment } = render(); expect(screen.queryByRole("button", { name: "Add" })).toBeNull(); expect(asFragment()).toMatchSnapshot(); + + await user.click(screen.getByRole("button", { name: "New message" })); + expect(defaultValue.createChatRoom).toHaveBeenCalled(); }); it("should display all the buttons when the menu is opened", async () => { diff --git a/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListHeaderView-test.tsx.snap b/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListHeaderView-test.tsx.snap index 1eca5609ad..731a333f75 100644 --- a/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListHeaderView-test.tsx.snap +++ b/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListHeaderView-test.tsx.snap @@ -135,6 +135,35 @@ exports[` compose menu should not display the compose menu + `; diff --git a/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListPanel-test.tsx.snap b/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListPanel-test.tsx.snap index 6421601173..28f3befc20 100644 --- a/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListPanel-test.tsx.snap +++ b/test/unit-tests/components/views/rooms/RoomListPanel/__snapshots__/RoomListPanel-test.tsx.snap @@ -23,6 +23,35 @@ exports[` should not render the RoomListSearch component when U Home +