/* Copyright 2024, 2025 New Vector Ltd. Copyright 2020 The Matrix.org Foundation C.I.C. 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, { useEffect, useState, type JSX } from "react"; import classNames from "classnames"; import { MenuItem, Separator, ToggleMenuItem, Text, Badge, Heading, IconButton, Link, Search, Form, } from "@vector-im/compound-web"; import FavouriteIcon from "@vector-im/compound-design-tokens/assets/web/icons/favourite"; import UserAddIcon from "@vector-im/compound-design-tokens/assets/web/icons/user-add"; import LinkIcon from "@vector-im/compound-design-tokens/assets/web/icons/link"; import SettingsIcon from "@vector-im/compound-design-tokens/assets/web/icons/settings"; import ExportArchiveIcon from "@vector-im/compound-design-tokens/assets/web/icons/export-archive"; import LeaveIcon from "@vector-im/compound-design-tokens/assets/web/icons/leave"; import FilesIcon from "@vector-im/compound-design-tokens/assets/web/icons/files"; import ExtensionsIcon from "@vector-im/compound-design-tokens/assets/web/icons/extensions"; import UserProfileIcon from "@vector-im/compound-design-tokens/assets/web/icons/user-profile"; import ThreadsIcon from "@vector-im/compound-design-tokens/assets/web/icons/threads"; import PollsIcon from "@vector-im/compound-design-tokens/assets/web/icons/polls"; import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin"; import LockIcon from "@vector-im/compound-design-tokens/assets/web/icons/lock-solid"; import LockOffIcon from "@vector-im/compound-design-tokens/assets/web/icons/lock-off"; import PublicIcon from "@vector-im/compound-design-tokens/assets/web/icons/public"; import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error"; import ErrorSolidIcon from "@vector-im/compound-design-tokens/assets/web/icons/error-solid"; import ChevronDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-down"; import { JoinRule, type Room } from "matrix-js-sdk/src/matrix"; import { Box, Flex, HistoryVisibilityBadge, LinkedText, StatusTextView } from "@element-hq/web-shared-components"; import BaseCard from "./BaseCard.tsx"; import { _t } from "../../../languageHandler"; import RoomAvatar from "../avatars/RoomAvatar.tsx"; import { E2EStatus } from "../../../utils/ShieldUtils.ts"; import { type RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks.ts"; import { topicToHtml } from "../../../HtmlUtils.tsx"; import { useRoomSummaryCardViewModel } from "../../viewmodels/right_panel/RoomSummaryCardViewModel"; import { useRoomTopicViewModel } from "../../viewmodels/right_panel/RoomSummaryCardTopicViewModel"; import { useRoomName } from "../../../hooks/useRoomName.ts"; interface IProps { room: Room; permalinkCreator: RoomPermalinkCreator; onSearchChange?: (term: string) => void; onSearchCancel?: () => void; focusRoomSearch?: boolean; searchTerm?: string; } const RoomTopic: React.FC> = ({ room }): JSX.Element | null => { const vm = useRoomTopicViewModel(room); const body = topicToHtml(vm.topic?.text, vm.topic?.html); if (!body && !vm.canEditTopic) { return null; } if (!body) { return ( {_t("right_panel|add_topic")} ); } const content = vm.expanded ? {body} : body; return ( {content} {vm.expanded && vm.canEditTopic && ( {_t("action|edit")} )} ); }; const RoomSummaryCardView: React.FC = ({ room, permalinkCreator, onSearchChange, onSearchCancel, focusRoomSearch, searchTerm = "", }) => { const vm = useRoomSummaryCardViewModel(room, permalinkCreator, onSearchCancel); // XXX: this name should be part of the view model const name = useRoomName(room); // The search field is controlled and onSearchChange is debounced in RoomView, // so we need to set the value of the input right away const [searchValue, setSearchValue] = useState(searchTerm); useEffect(() => { setSearchValue(searchTerm); }, [searchTerm]); const roomInfo = (
{name} {vm.userStatus && } {vm.alias} {!vm.isDirectMessage && vm.roomJoinRule === JoinRule.Public && ( {_t("common|public_room")} )} {vm.isRoomEncrypted && vm.e2eStatus !== E2EStatus.Warning && ( {_t("common|encrypted")} )} {!vm.isRoomEncrypted && ( {_t("common|unencrypted")} )} {vm.e2eStatus === E2EStatus.Warning && ( {_t("common|not_trusted")} )}
); const header = onSearchChange && ( e.preventDefault()}> { setSearchValue(e.currentTarget.value); onSearchChange(e.currentTarget.value); }} value={searchValue} className="mx_no_textinput" ref={vm.searchInputRef} autoFocus={focusRoomSearch} onKeyDown={vm.onUpdateSearchInput} /> ); return ( {roomInfo}
{!vm.isVideoRoom && ( <> {vm.pinCount} )} {!vm.isVideoRoom && ( <> )}
); }; export default RoomSummaryCardView;