Hide room header buttons if the room hasn't been created yet. (#31092)
* Hide room header buttons if the room isn't ready * update test * update unit tests * Remove on-click actions
This commit is contained in:
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX, useCallback, useMemo, useState } from "react";
|
||||
import { Body as BodyText, Button, IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web";
|
||||
import { Text, Button, IconButton, Menu, MenuItem, Tooltip } from "@vector-im/compound-web";
|
||||
import VideoCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid";
|
||||
import VoiceCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/voice-call-solid";
|
||||
import CloseCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/close";
|
||||
@@ -54,22 +54,15 @@ import { RoomSettingsTab } from "../../dialogs/RoomSettingsDialog.tsx";
|
||||
import { useScopedRoomContext } from "../../../../contexts/ScopedRoomContext.tsx";
|
||||
import { ToggleableIcon } from "./toggle/ToggleableIcon.tsx";
|
||||
import { CurrentRightPanelPhaseContextProvider } from "../../../../contexts/CurrentRightPanelPhaseContext.tsx";
|
||||
import { type LocalRoom } from "../../../../models/LocalRoom.ts";
|
||||
import { LocalRoom } from "../../../../models/LocalRoom.ts";
|
||||
|
||||
export default function RoomHeader({
|
||||
function RoomHeaderButtons({
|
||||
room,
|
||||
additionalButtons,
|
||||
oobData,
|
||||
}: {
|
||||
room: Room | LocalRoom;
|
||||
room: Room;
|
||||
additionalButtons?: ViewRoomOpts["buttons"];
|
||||
oobData?: IOOBData;
|
||||
}): JSX.Element {
|
||||
const client = useMatrixClientContext();
|
||||
|
||||
const roomName = useRoomName(room);
|
||||
const joinRule = useRoomState(room, (state) => state.getJoinRule());
|
||||
|
||||
const members = useRoomMembers(room, 2500);
|
||||
const memberCount = useRoomMemberCount(room, { throttleWait: 2500, includeInvited: true });
|
||||
|
||||
@@ -101,12 +94,9 @@ export default function RoomHeader({
|
||||
|
||||
const dmMember = useDmMember(room);
|
||||
const isDirectMessage = !!dmMember;
|
||||
const e2eStatus = useEncryptionStatus(client, room);
|
||||
|
||||
const notificationsEnabled = useFeatureEnabled("feature_notifications");
|
||||
|
||||
const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
|
||||
|
||||
const videoClick = useCallback(
|
||||
(ev: React.MouseEvent) => videoCallClick(ev, callOptions[0]),
|
||||
[callOptions, videoCallClick],
|
||||
@@ -242,7 +232,118 @@ export default function RoomHeader({
|
||||
isVideoRoom ||
|
||||
roomContext.mainSplitContentType === MainSplitContentType.MaximisedWidget ||
|
||||
roomContext.mainSplitContentType === MainSplitContentType.Call;
|
||||
return (
|
||||
<>
|
||||
{additionalButtons?.map((props) => {
|
||||
const label = props.label();
|
||||
|
||||
return (
|
||||
<Tooltip label={label} key={props.id}>
|
||||
<IconButton
|
||||
aria-label={label}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
props.onClick();
|
||||
}}
|
||||
>
|
||||
{typeof props.icon === "function" ? props.icon() : props.icon}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
|
||||
{isViewingCall && <CallGuestLinkButton room={room} />}
|
||||
|
||||
{hasActiveCallSession && !isConnectedToCall && !isViewingCall ? (
|
||||
joinCallButton
|
||||
) : (
|
||||
<>
|
||||
{!isVideoRoom && videoCallButton}
|
||||
{!useElementCallExclusively && !isVideoRoom && voiceCallButton}
|
||||
</>
|
||||
)}
|
||||
|
||||
{showChatButton && <VideoRoomChatButton room={room} />}
|
||||
|
||||
<Tooltip label={_t("common|threads")}>
|
||||
<IconButton
|
||||
indicator={notificationLevelToIndicator(threadNotifications)}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.ThreadPanel);
|
||||
PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
|
||||
}}
|
||||
aria-label={_t("common|threads")}
|
||||
>
|
||||
<ToggleableIcon Icon={ThreadsIcon} phase={RightPanelPhases.ThreadPanel} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{notificationsEnabled && (
|
||||
<Tooltip label={_t("notifications|enable_prompt_toast_title")}>
|
||||
<IconButton
|
||||
indicator={notificationLevelToIndicator(globalNotificationState.level)}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
|
||||
}}
|
||||
aria-label={_t("notifications|enable_prompt_toast_title")}
|
||||
>
|
||||
<ToggleableIcon Icon={NotificationsIcon} phase={RightPanelPhases.NotificationPanel} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip label={_t("right_panel|room_summary_card|title")}>
|
||||
<IconButton
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
|
||||
}}
|
||||
aria-label={_t("right_panel|room_summary_card|title")}
|
||||
>
|
||||
<ToggleableIcon Icon={RoomInfoIcon} phase={RightPanelPhases.RoomSummary} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
{!isDirectMessage && (
|
||||
<Text as="div" size="sm" weight="medium">
|
||||
<FacePile
|
||||
className="mx_RoomHeader_members"
|
||||
members={members.slice(0, 3)}
|
||||
size="20px"
|
||||
overflow={false}
|
||||
viewUserOnClick={false}
|
||||
tooltipLabel={_t("room|header_face_pile_tooltip")}
|
||||
onClick={(e: ButtonEvent) => {
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.MemberList);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
aria-label={_t("common|n_members", { count: memberCount })}
|
||||
>
|
||||
{formatCount(memberCount)}
|
||||
</FacePile>
|
||||
</Text>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function RoomHeader({
|
||||
room,
|
||||
additionalButtons,
|
||||
oobData,
|
||||
}: {
|
||||
room: Room | LocalRoom;
|
||||
additionalButtons?: ViewRoomOpts["buttons"];
|
||||
oobData?: IOOBData;
|
||||
}): JSX.Element {
|
||||
const client = useMatrixClientContext();
|
||||
const roomName = useRoomName(room);
|
||||
const joinRule = useRoomState(room, (state) => state.getJoinRule());
|
||||
const dmMember = useDmMember(room);
|
||||
const isDirectMessage = !!dmMember;
|
||||
const e2eStatus = useEncryptionStatus(client, room);
|
||||
const askToJoinEnabled = useFeatureEnabled("feature_ask_to_join");
|
||||
const onAvatarClick = (): void => {
|
||||
defaultDispatcher.dispatch({
|
||||
action: "open_room_settings",
|
||||
@@ -256,23 +357,29 @@ export default function RoomHeader({
|
||||
<Flex as="header" align="center" gap="var(--cpd-space-3x)" className="mx_RoomHeader light-panel">
|
||||
<WithPresenceIndicator room={room} size="8px">
|
||||
{/* We hide this from the tabIndex list as it is a pointer shortcut and superfluous for a11y */}
|
||||
{/* Disable on-click actions until the room is created */}
|
||||
<RoomAvatar
|
||||
room={room}
|
||||
size="40px"
|
||||
oobData={oobData}
|
||||
onClick={onAvatarClick}
|
||||
onClick={room instanceof LocalRoom ? undefined : onAvatarClick}
|
||||
tabIndex={-1}
|
||||
aria-label={_t("room|header_avatar_open_settings_label")}
|
||||
/>
|
||||
</WithPresenceIndicator>
|
||||
{/* Disable on-click actions until the room is created */}
|
||||
<button
|
||||
aria-label={_t("right_panel|room_summary_card|title")}
|
||||
tabIndex={0}
|
||||
onClick={() => RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary)}
|
||||
onClick={
|
||||
room instanceof LocalRoom
|
||||
? undefined
|
||||
: () => RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary)
|
||||
}
|
||||
className="mx_RoomHeader_infoWrapper"
|
||||
>
|
||||
<Box flex="1" className="mx_RoomHeader_info">
|
||||
<BodyText
|
||||
<Text
|
||||
as="div"
|
||||
size="lg"
|
||||
weight="semibold"
|
||||
@@ -316,99 +423,12 @@ export default function RoomHeader({
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</BodyText>
|
||||
</Text>
|
||||
</Box>
|
||||
</button>
|
||||
|
||||
{additionalButtons?.map((props) => {
|
||||
const label = props.label();
|
||||
|
||||
return (
|
||||
<Tooltip label={label} key={props.id}>
|
||||
<IconButton
|
||||
aria-label={label}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
props.onClick();
|
||||
}}
|
||||
>
|
||||
{typeof props.icon === "function" ? props.icon() : props.icon}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
|
||||
{isViewingCall && <CallGuestLinkButton room={room} />}
|
||||
|
||||
{hasActiveCallSession && !isConnectedToCall && !isViewingCall ? (
|
||||
joinCallButton
|
||||
) : (
|
||||
<>
|
||||
{!isVideoRoom && videoCallButton}
|
||||
{!useElementCallExclusively && !isVideoRoom && voiceCallButton}
|
||||
</>
|
||||
)}
|
||||
|
||||
{showChatButton && <VideoRoomChatButton room={room} />}
|
||||
|
||||
<Tooltip label={_t("common|threads")}>
|
||||
<IconButton
|
||||
indicator={notificationLevelToIndicator(threadNotifications)}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.ThreadPanel);
|
||||
PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
|
||||
}}
|
||||
aria-label={_t("common|threads")}
|
||||
>
|
||||
<ToggleableIcon Icon={ThreadsIcon} phase={RightPanelPhases.ThreadPanel} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{notificationsEnabled && (
|
||||
<Tooltip label={_t("notifications|enable_prompt_toast_title")}>
|
||||
<IconButton
|
||||
indicator={notificationLevelToIndicator(globalNotificationState.level)}
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.NotificationPanel);
|
||||
}}
|
||||
aria-label={_t("notifications|enable_prompt_toast_title")}
|
||||
>
|
||||
<ToggleableIcon Icon={NotificationsIcon} phase={RightPanelPhases.NotificationPanel} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip label={_t("right_panel|room_summary_card|title")}>
|
||||
<IconButton
|
||||
onClick={(evt) => {
|
||||
evt.stopPropagation();
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.RoomSummary);
|
||||
}}
|
||||
aria-label={_t("right_panel|room_summary_card|title")}
|
||||
>
|
||||
<ToggleableIcon Icon={RoomInfoIcon} phase={RightPanelPhases.RoomSummary} />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
{!isDirectMessage && (
|
||||
<BodyText as="div" size="sm" weight="medium">
|
||||
<FacePile
|
||||
className="mx_RoomHeader_members"
|
||||
members={members.slice(0, 3)}
|
||||
size="20px"
|
||||
overflow={false}
|
||||
viewUserOnClick={false}
|
||||
tooltipLabel={_t("room|header_face_pile_tooltip")}
|
||||
onClick={(e: ButtonEvent) => {
|
||||
RightPanelStore.instance.showOrHidePhase(RightPanelPhases.MemberList);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
aria-label={_t("common|n_members", { count: memberCount })}
|
||||
>
|
||||
{formatCount(memberCount)}
|
||||
</FacePile>
|
||||
</BodyText>
|
||||
{/* If the room is local-only then we don't want to show any additional buttons, as it won't work */}
|
||||
{room instanceof LocalRoom === false && (
|
||||
<RoomHeaderButtons room={room} additionalButtons={additionalButtons} />
|
||||
)}
|
||||
</Flex>
|
||||
{askToJoinEnabled && <RoomKnocksBar room={room} />}
|
||||
|
||||
Reference in New Issue
Block a user