/* * Copyright 2026 Element Creations 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 React, { type JSX, type ReactNode } from "react"; import { useViewModel, type ViewModel } from "../../core/viewmodel"; import { RoomListPrimaryFilters, type FilterId } from "../RoomListPrimaryFilters"; import { RoomListLoadingSkeleton } from "./RoomListLoadingSkeleton"; import { RoomListEmptyStateView } from "./RoomListEmptyStateView"; import { VirtualizedRoomListView, type RoomListViewState } from "../VirtualizedRoomListView"; import { type Room, type RoomListItemViewModel } from "../VirtualizedRoomListView/RoomListItemWrapper/RoomListItemView"; import { type RoomListSectionHeaderViewModel } from "../VirtualizedRoomListView/RoomListSectionHeaderView"; import { type ToastType, RoomListToast } from "./RoomListToast"; import styles from "./RoomListView.module.css"; import { Flex } from "../../core/utils/Flex"; export type RoomListSection = { /** Unique identifier for the section */ id: string; /** Array of room IDs that belong to this section */ roomIds: string[]; }; /** * Snapshot for the room list view */ export type RoomListViewSnapshot = { /** Whether the rooms are currently loading */ isLoadingRooms: boolean; /** Whether the room list is empty */ isRoomListEmpty: boolean; /** Array of filter IDs */ filterIds: FilterId[]; /** Currently active filter ID (if any) */ activeFilterId?: FilterId; /** Room list state */ roomListState: RoomListViewState; /** Array of sections in the room list */ sections: RoomListSection[]; /** Optional description for the empty state */ emptyStateDescription?: string; /** Optional action element for the empty state */ emptyStateAction?: ReactNode; /** Whether the user can create rooms */ canCreateRoom?: boolean; /** Whether the room list is displayed as a flat list */ isFlatList: boolean; /** Optional toast to display */ toast?: ToastType; }; /** * Actions interface for room list operations */ export interface RoomListViewActions { /** Called when a filter is toggled */ onToggleFilter: (filterId: FilterId) => void; /** Called to create a new chat room */ createChatRoom: () => void; /** Called to create a new room */ createRoom: () => void; /** * Get view model for a specific room (virtualization API) * Allow undefined to be returned if we don't have a view model for the room. In this case the room will not be rendered. */ getRoomItemViewModel: (roomId: string) => RoomListItemViewModel | undefined; /** Called when the visible range changes (virtualization API) */ updateVisibleRooms: (startIndex: number, endIndex: number) => void; /** Get view model for a specific section header (virtualization API) */ getSectionHeaderViewModel: (sectionId: string) => RoomListSectionHeaderViewModel; /** Called to close the toast message */ closeToast: () => void; /** Called to change the section of a room */ changeRoomSection: (roomId: string, tag: string) => void; } /** * The view model type for the room list view */ export type RoomListViewModel = ViewModel; /** * Props for RoomListView component */ export interface RoomListViewProps { /** The view model containing all data and callbacks */ vm: RoomListViewModel; /** Render function for room avatar */ renderAvatar: (room: Room) => ReactNode; /** Optional callback for keyboard events on the room list */ onKeyDown?: (e: React.KeyboardEvent) => void; } /** * Room list view component that manages filters, loading states, empty states, and the room list. */ export const RoomListView: React.FC = ({ vm, renderAvatar, onKeyDown }): JSX.Element => { const snapshot = useViewModel(vm); let listBody: ReactNode; if (snapshot.isLoadingRooms) { listBody = ; } else if (snapshot.isRoomListEmpty) { listBody = ; } else { listBody = ; } return ( <>
{listBody} {snapshot.toast && } ); };