* feat: add video call and EC call to room list item vm * feat: add video call notification decoration to notification decoration component * feat: add video call support to room list item view * feat: add new RoomAvatarView component * feat: deprecate `DecoratedRoomAvatar` * feat: use `RoomAvatarView` in room list item * feat: allow custom class for `RoomAvatar` * test: update notification decoration * test: update room list item view * test: update room list snapshot * test: add tests for room avatar vm * test: add tests for room avatar view * test(e2e): update snapshots * fix: video room creation rights * test: e2e add test for public and video room
212 lines
6.5 KiB
TypeScript
212 lines
6.5 KiB
TypeScript
/*
|
|
* Copyright 2025 New Vector Ltd.
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
* Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import { useCallback } from "react";
|
|
import { JoinRule, type Room, RoomEvent, RoomType } from "matrix-js-sdk/src/matrix";
|
|
|
|
import { useFeatureEnabled } from "../../../hooks/useSettings";
|
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
|
import PosthogTrackers from "../../../PosthogTrackers";
|
|
import { Action } from "../../../dispatcher/actions";
|
|
import { useEventEmitterState, useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
|
|
import {
|
|
getMetaSpaceName,
|
|
type MetaSpace,
|
|
type SpaceKey,
|
|
UPDATE_HOME_BEHAVIOUR,
|
|
UPDATE_SELECTED_SPACE,
|
|
} from "../../../stores/spaces";
|
|
import SpaceStore from "../../../stores/spaces/SpaceStore";
|
|
import {
|
|
shouldShowSpaceSettings,
|
|
showCreateNewRoom,
|
|
showSpaceInvite,
|
|
showSpacePreferences,
|
|
showSpaceSettings,
|
|
} from "../../../utils/space";
|
|
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
|
|
import type { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
|
import { createRoom, hasCreateRoomRights } from "./utils";
|
|
|
|
/**
|
|
* Hook to get the active space and its title.
|
|
*/
|
|
function useSpace(): { activeSpace: Room | null; title: string } {
|
|
const [spaceKey, activeSpace] = useEventEmitterState<[SpaceKey, Room | null]>(
|
|
SpaceStore.instance,
|
|
UPDATE_SELECTED_SPACE,
|
|
() => [SpaceStore.instance.activeSpace, SpaceStore.instance.activeSpaceRoom],
|
|
);
|
|
const spaceName = useTypedEventEmitterState(activeSpace ?? undefined, RoomEvent.Name, () => activeSpace?.name);
|
|
const allRoomsInHome = useEventEmitterState(
|
|
SpaceStore.instance,
|
|
UPDATE_HOME_BEHAVIOUR,
|
|
() => SpaceStore.instance.allRoomsInHome,
|
|
);
|
|
|
|
const title = spaceName ?? getMetaSpaceName(spaceKey as MetaSpace, allRoomsInHome);
|
|
|
|
return {
|
|
activeSpace,
|
|
title,
|
|
};
|
|
}
|
|
|
|
export interface RoomListHeaderViewState {
|
|
/**
|
|
* The title of the room list
|
|
*/
|
|
title: string;
|
|
/**
|
|
* Whether to display the compose menu
|
|
* True if the user can create rooms
|
|
*/
|
|
displayComposeMenu: boolean;
|
|
/**
|
|
* Whether to display the space menu
|
|
* True if there is an active space
|
|
*/
|
|
displaySpaceMenu: boolean;
|
|
/**
|
|
* Whether the user can create rooms
|
|
*/
|
|
canCreateRoom: boolean;
|
|
/**
|
|
* Whether the user can create video rooms
|
|
*/
|
|
canCreateVideoRoom: boolean;
|
|
/**
|
|
* Whether the user can invite in the active space
|
|
*/
|
|
canInviteInSpace: boolean;
|
|
/**
|
|
* Whether the user can access space settings
|
|
*/
|
|
canAccessSpaceSettings: boolean;
|
|
/**
|
|
* Create a chat room
|
|
* @param e - The click event
|
|
*/
|
|
createChatRoom: (e: Event) => void;
|
|
/**
|
|
* Create a room
|
|
* @param e - The click event
|
|
*/
|
|
createRoom: (e: Event) => void;
|
|
/**
|
|
* Create a video room
|
|
*/
|
|
createVideoRoom: () => void;
|
|
/**
|
|
* Open the active space home
|
|
*/
|
|
openSpaceHome: () => void;
|
|
/**
|
|
* Display the space invite dialog
|
|
*/
|
|
inviteInSpace: () => void;
|
|
/**
|
|
* Open the space preferences
|
|
*/
|
|
openSpacePreferences: () => void;
|
|
/**
|
|
* Open the space settings
|
|
*/
|
|
openSpaceSettings: () => void;
|
|
}
|
|
|
|
/**
|
|
* View model for the RoomListHeader.
|
|
*/
|
|
export function useRoomListHeaderViewModel(): RoomListHeaderViewState {
|
|
const matrixClient = useMatrixClientContext();
|
|
const { activeSpace, title } = useSpace();
|
|
const isSpaceRoom = Boolean(activeSpace);
|
|
|
|
const canCreateRoom = hasCreateRoomRights(matrixClient, activeSpace);
|
|
const canCreateVideoRoom = useFeatureEnabled("feature_video_rooms") && canCreateRoom;
|
|
const displayComposeMenu = canCreateRoom;
|
|
const displaySpaceMenu = isSpaceRoom;
|
|
const canInviteInSpace = Boolean(
|
|
activeSpace?.getJoinRule() === JoinRule.Public || activeSpace?.canInvite(matrixClient.getSafeUserId()),
|
|
);
|
|
const canAccessSpaceSettings = Boolean(activeSpace && shouldShowSpaceSettings(activeSpace));
|
|
|
|
/* Actions */
|
|
|
|
const createChatRoom = useCallback((e: Event) => {
|
|
defaultDispatcher.fire(Action.CreateChat);
|
|
PosthogTrackers.trackInteraction("WebRoomListHeaderPlusMenuCreateChatItem", e);
|
|
}, []);
|
|
|
|
const createRoomMemoized = useCallback(
|
|
(e: Event) => {
|
|
createRoom(activeSpace);
|
|
PosthogTrackers.trackInteraction("WebRoomListHeaderPlusMenuCreateRoomItem", e);
|
|
},
|
|
[activeSpace],
|
|
);
|
|
|
|
const elementCallVideoRoomsEnabled = useFeatureEnabled("feature_element_call_video_rooms");
|
|
const createVideoRoom = useCallback(() => {
|
|
const type = elementCallVideoRoomsEnabled ? RoomType.UnstableCall : RoomType.ElementVideo;
|
|
if (activeSpace) {
|
|
showCreateNewRoom(activeSpace, type);
|
|
} else {
|
|
defaultDispatcher.dispatch({
|
|
action: Action.CreateRoom,
|
|
type,
|
|
});
|
|
}
|
|
}, [activeSpace, elementCallVideoRoomsEnabled]);
|
|
|
|
const openSpaceHome = useCallback(() => {
|
|
// openSpaceHome is only available when there is an active space
|
|
if (!activeSpace) return;
|
|
defaultDispatcher.dispatch<ViewRoomPayload>({
|
|
action: Action.ViewRoom,
|
|
room_id: activeSpace.roomId,
|
|
metricsTrigger: undefined,
|
|
});
|
|
}, [activeSpace]);
|
|
|
|
const inviteInSpace = useCallback(() => {
|
|
// inviteInSpace is only available when there is an active space
|
|
if (!activeSpace) return;
|
|
showSpaceInvite(activeSpace);
|
|
}, [activeSpace]);
|
|
|
|
const openSpacePreferences = useCallback(() => {
|
|
// openSpacePreferences is only available when there is an active space
|
|
if (!activeSpace) return;
|
|
showSpacePreferences(activeSpace);
|
|
}, [activeSpace]);
|
|
|
|
const openSpaceSettings = useCallback(() => {
|
|
// openSpaceSettings is only available when there is an active space
|
|
if (!activeSpace) return;
|
|
showSpaceSettings(activeSpace);
|
|
}, [activeSpace]);
|
|
|
|
return {
|
|
title,
|
|
displayComposeMenu,
|
|
displaySpaceMenu,
|
|
canCreateRoom,
|
|
canCreateVideoRoom,
|
|
canInviteInSpace,
|
|
canAccessSpaceSettings,
|
|
createChatRoom,
|
|
createRoom: createRoomMemoized,
|
|
createVideoRoom,
|
|
openSpaceHome,
|
|
inviteInSpace,
|
|
openSpacePreferences,
|
|
openSpaceSettings,
|
|
};
|
|
}
|