Add a URL param for room ID

And consolidate our URL params logic
This commit is contained in:
Robin Townsend
2022-07-27 16:14:05 -04:00
parent 2a8cb3c4e2
commit cf56b24dda
13 changed files with 166 additions and 67 deletions

View File

@@ -21,14 +21,14 @@ import { usePageTitle } from "../usePageTitle";
export function GroupCallLoader({
client,
roomId,
roomIdOrAlias,
viaServers,
createPtt,
children,
}) {
const { loading, error, groupCall } = useLoadGroupCall(
client,
roomId,
roomIdOrAlias,
viaServers,
createPtt
);

View File

@@ -31,7 +31,7 @@ export function GroupCallView({
client,
isPasswordlessUser,
isEmbedded,
roomId,
roomIdOrAlias,
groupCall,
}) {
const {
@@ -89,7 +89,7 @@ export function GroupCallView({
return (
<PTTCallView
client={client}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
roomName={groupCall.room.name}
avatarUrl={avatarUrl}
groupCall={groupCall}
@@ -117,7 +117,7 @@ export function GroupCallView({
isScreensharing={isScreensharing}
localScreenshareFeed={localScreenshareFeed}
screenshareFeeds={screenshareFeeds}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
unencryptedEventsFromUsers={unencryptedEventsFromUsers}
/>
);
@@ -153,7 +153,7 @@ export function GroupCallView({
localVideoMuted={localVideoMuted}
toggleLocalVideoMuted={toggleLocalVideoMuted}
toggleMicrophoneMuted={toggleMicrophoneMuted}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
isEmbedded={isEmbedded}
/>
);

View File

@@ -65,7 +65,7 @@ export function InCallView({
toggleScreensharing,
isScreensharing,
screenshareFeeds,
roomId,
roomIdOrAlias,
unencryptedEventsFromUsers,
}) {
usePreventScroll();
@@ -184,7 +184,7 @@ export function InCallView({
)}
<OverflowMenu
inCall
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
client={client}
groupCall={groupCall}
showInvite={true}
@@ -201,7 +201,7 @@ export function InCallView({
{rageshakeRequestModalState.isOpen && (
<RageshakeRequestModal
{...rageshakeRequestModalProps}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
/>
)}
</div>

View File

@@ -20,7 +20,7 @@ import { CopyButton } from "../button";
import { getRoomUrl } from "../matrix-utils";
import styles from "./InviteModal.module.css";
export function InviteModal({ roomId, ...rest }) {
export function InviteModal({ roomIdOrAlias, ...rest }) {
return (
<Modal
title="Invite People"
@@ -30,7 +30,10 @@ export function InviteModal({ roomId, ...rest }) {
>
<ModalContent>
<p>Copy and share this meeting link</p>
<CopyButton className={styles.copyButton} value={getRoomUrl(roomId)} />
<CopyButton
className={styles.copyButton}
value={getRoomUrl(roomIdOrAlias)}
/>
</ModalContent>
</Modal>
);

View File

@@ -41,7 +41,7 @@ export function LobbyView({
localVideoMuted,
toggleLocalVideoMuted,
toggleMicrophoneMuted,
roomId,
roomIdOrAlias,
isEmbedded,
}) {
const { stream } = useCallFeed(localCallFeed);
@@ -95,7 +95,7 @@ export function LobbyView({
<VideoPreview
state={state}
client={client}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
microphoneMuted={microphoneMuted}
localVideoMuted={localVideoMuted}
toggleLocalVideoMuted={toggleLocalVideoMuted}
@@ -116,7 +116,7 @@ export function LobbyView({
<Body>Or</Body>
<CopyButton
variant="secondaryCopy"
value={getRoomUrl(roomId)}
value={getRoomUrl(roomIdOrAlias)}
className={styles.copyButton}
copiedMessage="Call link copied"
>

View File

@@ -30,7 +30,7 @@ import { TooltipTrigger } from "../Tooltip";
import { FeedbackModal } from "./FeedbackModal";
export function OverflowMenu({
roomId,
roomIdOrAlias,
inCall,
groupCall,
showInvite,
@@ -88,7 +88,7 @@ export function OverflowMenu({
</PopoverMenuTrigger>
{settingsModalState.isOpen && <SettingsModal {...settingsModalProps} />}
{inviteModalState.isOpen && (
<InviteModal roomId={roomId} {...inviteModalProps} />
<InviteModal roomIdOrAlias={roomIdOrAlias} {...inviteModalProps} />
)}
{feedbackModalState.isOpen && (
<FeedbackModal

View File

@@ -86,7 +86,7 @@ function getPromptText(
interface Props {
client: MatrixClient;
roomId: string;
roomIdOrAlias: string;
roomName: string;
avatarUrl: string;
groupCall: GroupCall;
@@ -98,7 +98,7 @@ interface Props {
export const PTTCallView: React.FC<Props> = ({
client,
roomId,
roomIdOrAlias,
roomName,
avatarUrl,
groupCall,
@@ -204,7 +204,7 @@ export const PTTCallView: React.FC<Props> = ({
<div className={styles.footer}>
<OverflowMenu
inCall
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
client={client}
groupCall={groupCall}
showInvite={false}
@@ -282,7 +282,7 @@ export const PTTCallView: React.FC<Props> = ({
</div>
{inviteModalState.isOpen && showControls && (
<InviteModal roomId={roomId} {...inviteModalProps} />
<InviteModal roomIdOrAlias={roomIdOrAlias} {...inviteModalProps} />
)}
</div>
);

View File

@@ -21,7 +21,11 @@ import { FieldRow, ErrorMessage } from "../input/Input";
import { useSubmitRageshake } from "../settings/submit-rageshake";
import { Body } from "../typography/Typography";
export function RageshakeRequestModal({ rageshakeRequestId, roomId, ...rest }) {
export function RageshakeRequestModal({
rageshakeRequestId,
roomIdOrAlias,
...rest
}) {
const { submitRageshake, sending, sent, error } = useSubmitRageshake();
useEffect(() => {
@@ -43,7 +47,7 @@ export function RageshakeRequestModal({ rageshakeRequestId, roomId, ...rest }) {
submitRageshake({
sendLogs: true,
rageshakeRequestId,
roomId,
roomIdOrAlias, // Possibly not a room ID, but oh well
})
}
disabled={sending}

View File

@@ -1,5 +1,5 @@
/*
Copyright 2021 New Vector Ltd
Copyright 2021-2022 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { useEffect, useMemo, useState } from "react";
import { useLocation, useParams } from "react-router-dom";
import React, { FC, useEffect, useState } from "react";
import { useClient } from "../ClientContext";
import { ErrorView, LoadingView } from "../FullScreenView";
import { RoomAuthView } from "./RoomAuthView";
import { GroupCallLoader } from "./GroupCallLoader";
import { GroupCallView } from "./GroupCallView";
import { useRoomParams } from "./useRoomParams";
import { MediaHandlerProvider } from "../settings/useMediaHandler";
import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser";
@@ -28,20 +28,12 @@ export function RoomPage() {
const { loading, isAuthenticated, error, client, isPasswordlessUser } =
useClient();
const { roomId: maybeRoomId } = useParams();
const { hash, search } = useLocation();
const [viaServers, isEmbedded, isPtt, displayName] = useMemo(() => {
const params = new URLSearchParams(search);
return [
params.getAll("via"),
params.has("embed"),
params.get("ptt") === "true",
params.get("displayName"),
];
}, [search]);
const roomId = (maybeRoomId || hash || "").toLowerCase();
const { registerPasswordlessUser, recaptchaId } =
useRegisterPasswordlessUser();
const { roomAlias, roomId, viaServers, isEmbedded, isPtt, displayName } =
useRoomParams();
const roomIdOrAlias = roomId ?? roomAlias;
if (!roomIdOrAlias) throw new Error("No room specified");
const { registerPasswordlessUser } = useRegisterPasswordlessUser();
const [isRegistering, setIsRegistering] = useState(false);
useEffect(() => {
@@ -76,14 +68,14 @@ export function RoomPage() {
<MediaHandlerProvider client={client}>
<GroupCallLoader
client={client}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
viaServers={viaServers}
createPtt={isPtt}
>
{(groupCall) => (
<GroupCallView
client={client}
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
groupCall={groupCall}
isPasswordlessUser={isPasswordlessUser}
isEmbedded={isEmbedded}

View File

@@ -30,7 +30,7 @@ import { useModalTriggerState } from "../Modal";
export function VideoPreview({
client,
state,
roomId,
roomIdOrAlias,
microphoneMuted,
localVideoMuted,
toggleLocalVideoMuted,
@@ -80,7 +80,7 @@ export function VideoPreview({
onPress={toggleLocalVideoMuted}
/>
<OverflowMenu
roomId={roomId}
roomIdOrAlias={roomIdOrAlias}
client={client}
feedbackModalState={feedbackModalState}
feedbackModalProps={feedbackModalProps}

93
src/room/useRoomParams.ts Normal file
View File

@@ -0,0 +1,93 @@
/*
Copyright 2022 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { useMemo } from "react";
import { useLocation } from "react-router-dom";
export interface RoomParams {
roomAlias: string | null;
roomId: string | null;
viaServers: string[];
// Whether the app is running in embedded mode, and should keep the user
// confined to the current room
isEmbedded: boolean;
// Whether to start a walkie-talkie call instead of a video call
isPtt: boolean;
// Whether to use end-to-end encryption
e2eEnabled: boolean;
// The user's ID (only used in Matroska mode)
userId: string | null;
// The display name to use for auto-registration
displayName: string | null;
// The device's ID (only used in Matroska mode)
deviceId: string | null;
}
/**
* Gets the room parameters for the current URL.
* @param {string} query The URL query string
* @param {string} fragment The URL fragment string
* @returns {RoomParams} The room parameters encoded in the URL
*/
export const getRoomParams = (
query: string = window.location.search,
fragment: string = window.location.hash
): RoomParams => {
const fragmentQueryStart = fragment.indexOf("?");
const fragmentParams = new URLSearchParams(
fragmentQueryStart === -1 ? "" : fragment.substring(fragmentQueryStart)
);
const queryParams = new URLSearchParams(query);
// Normally, room params should be encoded in the fragment so as to avoid
// leaking them to the server. However, we also check the normal query
// string for backwards compatibility with versions that only used that.
const hasParam = (name: string): boolean =>
fragmentParams.has(name) || queryParams.has(name);
const getParam = (name: string): string | null =>
fragmentParams.get(name) ?? queryParams.get(name);
const getAllParams = (name: string): string[] => [
...fragmentParams.getAll(name),
...queryParams.getAll(name),
];
// The part of the fragment before the ?
const fragmentRoute =
fragmentQueryStart === -1
? fragment
: fragment.substring(0, fragmentQueryStart);
return {
roomAlias: fragmentRoute.length > 1 ? fragmentRoute : null,
roomId: getParam("roomId"),
viaServers: getAllParams("via"),
isEmbedded: hasParam("embed"),
isPtt: hasParam("ptt"),
e2eEnabled: getParam("enableE2e") !== "false", // Defaults to true
userId: getParam("userId"),
displayName: getParam("displayName"),
deviceId: getParam("deviceId"),
};
};
/**
* Hook to simplify use of getRoomParams.
* @returns {RoomParams} The room parameters for the current URL
*/
export const useRoomParams = (): RoomParams => {
const { hash, search } = useLocation();
return useMemo(() => getRoomParams(search, hash), [search, hash]);
};