diff --git a/apps/web/src/components/views/elements/RoomTopic.tsx b/apps/web/src/components/views/elements/RoomTopic.tsx index f7b7751bb3..543037dad5 100644 --- a/apps/web/src/components/views/elements/RoomTopic.tsx +++ b/apps/web/src/components/views/elements/RoomTopic.tsx @@ -22,6 +22,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext"; import AccessibleButton, { type ButtonEvent } from "./AccessibleButton"; import { topicToHtml } from "../../../HtmlUtils"; import { tryTransformPermalinkToLocalHref } from "../../../utils/permalinks/Permalinks"; +import { showSpaceSettings } from "../../../utils/space"; interface IProps { room: Room; @@ -76,7 +77,13 @@ export default function RoomTopic({ room, className }: IProps): JSX.Element { kind="primary_outline" onClick={() => { modal.close(); - dis.dispatch({ action: "open_room_settings" }); + // SpaceRoomView renders this component for spaces too, and a space + // has its own settings dialog. + if (room.isSpaceRoom()) { + showSpaceSettings(room); + } else { + dis.dispatch({ action: "open_room_settings" }); + } }} > {_t("room|edit_topic")} diff --git a/apps/web/test/unit-tests/components/views/elements/RoomTopic-test.tsx b/apps/web/test/unit-tests/components/views/elements/RoomTopic-test.tsx index e53af36b71..56cd3b83eb 100644 --- a/apps/web/test/unit-tests/components/views/elements/RoomTopic-test.tsx +++ b/apps/web/test/unit-tests/components/views/elements/RoomTopic-test.tsx @@ -17,6 +17,9 @@ import { MatrixClientPeg } from "../../../../../src/MatrixClientPeg"; import RoomTopic from "../../../../../src/components/views/elements/RoomTopic"; import dis from "../../../../../src/dispatcher/dispatcher"; import { Action } from "../../../../../src/dispatcher/actions"; +import Modal from "../../../../../src/Modal"; +import { type ActionPayload } from "../../../../../src/dispatcher/payloads"; +import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext"; jest.mock("../../../../../src/dispatcher/dispatcher"); @@ -94,6 +97,62 @@ describe("", () => { expect(dis.fire).toHaveBeenCalledWith(Action.ShowRoomTopic); }); + describe("the edit topic button in the topic dialog", () => { + /** + * Render the topic, open the topic dialog and render its contents, so the + * "Edit topic" button can be clicked. + * @param isSpaceRoom whether the room should report itself as a space + */ + function renderTopicDialog(isSpaceRoom: boolean) { + const room = createRoom("a topic"); + jest.spyOn(room, "isSpaceRoom").mockReturnValue(isSpaceRoom); + jest.spyOn(room.currentState, "maySendStateEvent").mockReturnValue(true); + + const createDialog = jest + .spyOn(Modal, "createDialog") + .mockReturnValue({ close: jest.fn() } as unknown as ReturnType); + + render(, { + wrapper: ({ children }) => ( + + {children} + + ), + }); + + // The dispatcher is mocked for this suite, so drive the registered handler directly + // instead of firing Action.ShowRoomTopic through it. + const handler = jest.mocked(dis.register).mock.calls.at(-1)![0] as (payload: ActionPayload) => void; + handler({ action: Action.ShowRoomTopic }); + + const { description } = createDialog.mock.calls.at(-1)![1] as { description: React.ReactNode }; + render( + + <>{description} + , + ); + + return room; + } + + it("opens space settings for a space", () => { + const room = renderTopicDialog(true); + + fireEvent.click(screen.getByRole("button", { name: "Edit topic" })); + + expect(dis.dispatch).toHaveBeenCalledWith({ action: Action.OpenSpaceSettings, space: room }); + expect(dis.dispatch).not.toHaveBeenCalledWith({ action: "open_room_settings" }); + }); + + it("opens room settings for a room", () => { + renderTopicDialog(false); + + fireEvent.click(screen.getByRole("button", { name: "Edit topic" })); + + expect(dis.dispatch).toHaveBeenCalledWith({ action: "open_room_settings" }); + }); + }); + it("should open the tooltip when hovering a text", async () => { const topic = "room topic"; renderRoom(topic);