/* Copyright 2021-2024 New Vector Ltd. Copyright 2026 Element Creations Ltd. SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ import { type FC, useEffect, useState, type ReactNode, useRef } from "react"; import { type MatrixError } from "matrix-js-sdk"; import { logger } from "matrix-js-sdk/lib/logger"; import { Trans, useTranslation } from "react-i18next"; import { UnknownSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; import { useClientLegacy } from "../ClientContext"; import { ErrorPage, FullScreenView, LoadingPage } from "../FullScreenView"; import { RoomAuthView } from "./RoomAuthView"; import { ElementCallView } from "../ElementCallView"; import { useRoomIdentifier, useUrlParams } from "../UrlParams"; import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser"; import { HomePage } from "../home/HomePage"; import { CallTerminatedMessage, useLoadGroupCall } from "./useLoadGroupCall"; import { KnockLobbyView } from "./KnockLobbyView"; import { useProfile } from "../profile/useProfile"; import { useOptInAnalytics } from "../settings/settings"; import { Link } from "../button/Link"; import { ErrorView } from "../ErrorView"; export const RoomPage: FC = (): ReactNode => { const urlParams = useUrlParams(); const { confineToRoom, preload, header, displayName, skipLobby } = urlParams; const { t } = useTranslation(); const { roomAlias, roomId, viaServers } = useRoomIdentifier(); const roomIdOrAlias = roomId ?? roomAlias; if (!roomIdOrAlias) { logger.error("No room specified"); } const { registerPasswordlessUser } = useRegisterPasswordlessUser(); const [isRegistering, setIsRegistering] = useState(false); const { loading, authenticated, client, error, passwordlessUser } = useClientLegacy(); const { avatarUrl, displayName: userDisplayName } = useProfile(client); const groupCallState = useLoadGroupCall(client, roomIdOrAlias, viaServers); useEffect(() => { // If we've finished loading, are not already authed and we've been given a display name as // a URL param, automatically register a passwordless user if (!loading && !authenticated && displayName && !urlParams.isWidget) { setIsRegistering(true); registerPasswordlessUser(displayName) .catch((e) => { logger.error("Failed to register passwordless user", e); }) .finally(() => { setIsRegistering(false); }); } }, [ loading, authenticated, displayName, urlParams.isWidget, setIsRegistering, registerPasswordlessUser, ]); const [optInAnalytics, setOptInAnalytics] = useOptInAnalytics(); useEffect(() => { // During the beta, opt into analytics by default if (optInAnalytics === null && setOptInAnalytics) setOptInAnalytics(true); }, [optInAnalytics, setOptInAnalytics]); const wasInWaitForInviteState = useRef(false); useEffect(() => { if (groupCallState.kind === "loaded" && wasInWaitForInviteState.current) { logger.log("Play join sound 'Not yet implemented'"); } }, [groupCallState.kind]); const groupCallView = (): ReactNode => { switch (groupCallState.kind) { case "loaded": return ( ); case "waitForInvite": case "canKnock": { wasInWaitForInviteState.current = wasInWaitForInviteState.current || groupCallState.kind === "waitForInvite"; return ( ); } case "loading": return (

{t("common.loading")}

); case "failed": wasInWaitForInviteState.current = false; if ((groupCallState.error as MatrixError).errcode === "M_NOT_FOUND") { return (

That link doesn't appear to belong to any existing call. Check that you have the right link, or{" "} create a new one.

); } else if (groupCallState.error instanceof CallTerminatedMessage) { return (

{groupCallState.error.messageBody}

{groupCallState.error.reason && (

{t("group_call_loader.reason", { reason: groupCallState.error.reason, })}

)}
); } else { return ; } default: return <> ; } }; if (loading || isRegistering) return ; if (error) return ; if (!client) return ; // TODO: This doesn't belong here, the app routes need to be reworked if (!roomIdOrAlias) return ; return groupCallView(); };