/* Copyright 2024 New Vector Ltd. Copyright 2022 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, { type JSX, type FC, useContext, useState } from "react"; import { type Room, JoinRule } from "matrix-js-sdk/src/matrix"; import { KnownMembership } from "matrix-js-sdk/src/types"; import { _t } from "../../../languageHandler"; import defaultDispatcher from "../../../dispatcher/dispatcher"; import { Action } from "../../../dispatcher/actions"; import { UserTab } from "../dialogs/UserTab"; import { EffectiveMembership, getEffectiveMembership } from "../../../utils/membership"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import { useDispatcher } from "../../../hooks/useDispatcher"; import { useRoomState } from "../../../hooks/useRoomState"; import { useMyRoomMembership } from "../../../hooks/useRoomMembers"; import AccessibleButton from "../elements/AccessibleButton"; import InlineSpinner from "../elements/InlineSpinner"; import RoomName from "../elements/RoomName"; import RoomTopic from "../elements/RoomTopic"; import RoomFacePile from "../elements/RoomFacePile"; import RoomAvatar from "../avatars/RoomAvatar"; import MemberAvatar from "../avatars/MemberAvatar"; import { BetaPill } from "../beta/BetaCard"; import RoomInfoLine from "./RoomInfoLine"; import { isVideoRoom as calcIsVideoRoom } from "../../../utils/video-rooms"; interface IProps { room: Room; onJoinButtonClicked: () => void; onRejectButtonClicked: () => void; } // XXX This component is currently only used for spaces and video rooms, though // surely we should expand its use to all rooms for consistency? This already // handles the text room case, though we would need to add support for ignoring // and viewing invite reasons to achieve parity with the default invite screen. const RoomPreviewCard: FC = ({ room, onJoinButtonClicked, onRejectButtonClicked }) => { const cli = useContext(MatrixClientContext); const isVideoRoom = calcIsVideoRoom(room); const myMembership = useMyRoomMembership(room); useDispatcher(defaultDispatcher, (payload) => { if (payload.action === Action.JoinRoomError && payload.roomId === room.roomId) { setBusy(false); // stop the spinner, join failed } }); const [busy, setBusy] = useState(false); const joinRule = useRoomState(room, (state) => state.getJoinRule()); const cannotJoin = getEffectiveMembership(myMembership) === EffectiveMembership.Leave && joinRule !== JoinRule.Public; const viewLabs = (): void => defaultDispatcher.dispatch({ action: Action.ViewUserSettings, initialTabId: UserTab.Labs, }); let inviterSection: JSX.Element | null = null; let joinButtons: JSX.Element; if (myMembership === KnownMembership.Join) { joinButtons = ( { defaultDispatcher.dispatch({ action: "leave_room", room_id: room.roomId, }); }} > {_t("action|leave")} ); } else if (myMembership === KnownMembership.Invite) { const inviteSender = room.getMember(cli.getUserId()!)?.events.member?.getSender(); if (inviteSender) { const inviter = room.getMember(inviteSender); inviterSection = (
{_t( "room|invites_you_text", {}, { inviter: () => {inviter?.name || inviteSender}, }, )}
{inviter ?
{inviteSender}
: null}
); } joinButtons = ( <> { setBusy(true); onRejectButtonClicked(); }} > {_t("action|decline")} { setBusy(true); onJoinButtonClicked(); }} > {_t("action|accept")} ); } else { joinButtons = ( { onJoinButtonClicked(); if (!cli.isGuest()) { // user will be shown a modal that won't fire a room join error setBusy(true); } }} disabled={cannotJoin} > {_t("action|join")} ); } if (busy) { joinButtons = ; } let avatarRow: JSX.Element; if (isVideoRoom) { avatarRow = ( <>
); } else if (room.isSpaceRoom()) { avatarRow = ; } else { avatarRow = ; } return (
{inviterSection}
{avatarRow}

{room.getJoinRule() === "public" && } {cannotJoin ? (
{_t("room|join_failed_needs_invite", { roomName: room.name })}
) : null}
{joinButtons}
); }; export default RoomPreviewCard;