@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
77*/
88
99import React , { type JSX , useCallback , useMemo , useState } from "react" ;
10- import { Body as BodyText , Button , IconButton , Menu , MenuItem , Tooltip } from "@vector-im/compound-web" ;
10+ import { Text , Button , IconButton , Menu , MenuItem , Tooltip } from "@vector-im/compound-web" ;
1111import VideoCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/video-call-solid" ;
1212import VoiceCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/voice-call-solid" ;
1313import CloseCallIcon from "@vector-im/compound-design-tokens/assets/web/icons/close" ;
@@ -54,22 +54,15 @@ import { RoomSettingsTab } from "../../dialogs/RoomSettingsDialog.tsx";
5454import { useScopedRoomContext } from "../../../../contexts/ScopedRoomContext.tsx" ;
5555import { ToggleableIcon } from "./toggle/ToggleableIcon.tsx" ;
5656import { CurrentRightPanelPhaseContextProvider } from "../../../../contexts/CurrentRightPanelPhaseContext.tsx" ;
57- import { type LocalRoom } from "../../../../models/LocalRoom.ts" ;
57+ import { LocalRoom } from "../../../../models/LocalRoom.ts" ;
5858
59- export default function RoomHeader ( {
59+ function RoomHeaderButtons ( {
6060 room,
6161 additionalButtons,
62- oobData,
6362} : {
64- room : Room | LocalRoom ;
63+ room : Room ;
6564 additionalButtons ?: ViewRoomOpts [ "buttons" ] ;
66- oobData ?: IOOBData ;
6765} ) : JSX . Element {
68- const client = useMatrixClientContext ( ) ;
69-
70- const roomName = useRoomName ( room ) ;
71- const joinRule = useRoomState ( room , ( state ) => state . getJoinRule ( ) ) ;
72-
7366 const members = useRoomMembers ( room , 2500 ) ;
7467 const memberCount = useRoomMemberCount ( room , { throttleWait : 2500 , includeInvited : true } ) ;
7568
@@ -101,12 +94,9 @@ export default function RoomHeader({
10194
10295 const dmMember = useDmMember ( room ) ;
10396 const isDirectMessage = ! ! dmMember ;
104- const e2eStatus = useEncryptionStatus ( client , room ) ;
10597
10698 const notificationsEnabled = useFeatureEnabled ( "feature_notifications" ) ;
10799
108- const askToJoinEnabled = useFeatureEnabled ( "feature_ask_to_join" ) ;
109-
110100 const videoClick = useCallback (
111101 ( ev : React . MouseEvent ) => videoCallClick ( ev , callOptions [ 0 ] ) ,
112102 [ callOptions , videoCallClick ] ,
@@ -242,7 +232,118 @@ export default function RoomHeader({
242232 isVideoRoom ||
243233 roomContext . mainSplitContentType === MainSplitContentType . MaximisedWidget ||
244234 roomContext . mainSplitContentType === MainSplitContentType . Call ;
235+ return (
236+ < >
237+ { additionalButtons ?. map ( ( props ) => {
238+ const label = props . label ( ) ;
239+
240+ return (
241+ < Tooltip label = { label } key = { props . id } >
242+ < IconButton
243+ aria-label = { label }
244+ onClick = { ( event ) => {
245+ event . stopPropagation ( ) ;
246+ props . onClick ( ) ;
247+ } }
248+ >
249+ { typeof props . icon === "function" ? props . icon ( ) : props . icon }
250+ </ IconButton >
251+ </ Tooltip >
252+ ) ;
253+ } ) }
254+
255+ { isViewingCall && < CallGuestLinkButton room = { room } /> }
245256
257+ { hasActiveCallSession && ! isConnectedToCall && ! isViewingCall ? (
258+ joinCallButton
259+ ) : (
260+ < >
261+ { ! isVideoRoom && videoCallButton }
262+ { ! useElementCallExclusively && ! isVideoRoom && voiceCallButton }
263+ </ >
264+ ) }
265+
266+ { showChatButton && < VideoRoomChatButton room = { room } /> }
267+
268+ < Tooltip label = { _t ( "common|threads" ) } >
269+ < IconButton
270+ indicator = { notificationLevelToIndicator ( threadNotifications ) }
271+ onClick = { ( evt ) => {
272+ evt . stopPropagation ( ) ;
273+ RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . ThreadPanel ) ;
274+ PosthogTrackers . trackInteraction ( "WebRoomHeaderButtonsThreadsButton" , evt ) ;
275+ } }
276+ aria-label = { _t ( "common|threads" ) }
277+ >
278+ < ToggleableIcon Icon = { ThreadsIcon } phase = { RightPanelPhases . ThreadPanel } />
279+ </ IconButton >
280+ </ Tooltip >
281+ { notificationsEnabled && (
282+ < Tooltip label = { _t ( "notifications|enable_prompt_toast_title" ) } >
283+ < IconButton
284+ indicator = { notificationLevelToIndicator ( globalNotificationState . level ) }
285+ onClick = { ( evt ) => {
286+ evt . stopPropagation ( ) ;
287+ RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . NotificationPanel ) ;
288+ } }
289+ aria-label = { _t ( "notifications|enable_prompt_toast_title" ) }
290+ >
291+ < ToggleableIcon Icon = { NotificationsIcon } phase = { RightPanelPhases . NotificationPanel } />
292+ </ IconButton >
293+ </ Tooltip >
294+ ) }
295+
296+ < Tooltip label = { _t ( "right_panel|room_summary_card|title" ) } >
297+ < IconButton
298+ onClick = { ( evt ) => {
299+ evt . stopPropagation ( ) ;
300+ RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . RoomSummary ) ;
301+ } }
302+ aria-label = { _t ( "right_panel|room_summary_card|title" ) }
303+ >
304+ < ToggleableIcon Icon = { RoomInfoIcon } phase = { RightPanelPhases . RoomSummary } />
305+ </ IconButton >
306+ </ Tooltip >
307+
308+ { ! isDirectMessage && (
309+ < Text as = "div" size = "sm" weight = "medium" >
310+ < FacePile
311+ className = "mx_RoomHeader_members"
312+ members = { members . slice ( 0 , 3 ) }
313+ size = "20px"
314+ overflow = { false }
315+ viewUserOnClick = { false }
316+ tooltipLabel = { _t ( "room|header_face_pile_tooltip" ) }
317+ onClick = { ( e : ButtonEvent ) => {
318+ RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . MemberList ) ;
319+ e . stopPropagation ( ) ;
320+ } }
321+ aria-label = { _t ( "common|n_members" , { count : memberCount } ) }
322+ >
323+ { formatCount ( memberCount ) }
324+ </ FacePile >
325+ </ Text >
326+ ) }
327+ </ >
328+ ) ;
329+ }
330+
331+ export default function RoomHeader ( {
332+ room,
333+ additionalButtons,
334+ oobData,
335+ } : {
336+ room : Room | LocalRoom ;
337+ additionalButtons ?: ViewRoomOpts [ "buttons" ] ;
338+ oobData ?: IOOBData ;
339+ } ) : JSX . Element {
340+ const client = useMatrixClientContext ( ) ;
341+ const roomName = useRoomName ( room ) ;
342+ const joinRule = useRoomState ( room , ( state ) => state . getJoinRule ( ) ) ;
343+ const dmMember = useDmMember ( room ) ;
344+ const isDirectMessage = ! ! dmMember ;
345+ const e2eStatus = useEncryptionStatus ( client , room ) ;
346+ const askToJoinEnabled = useFeatureEnabled ( "feature_ask_to_join" ) ;
246347 const onAvatarClick = ( ) : void => {
247348 defaultDispatcher . dispatch ( {
248349 action : "open_room_settings" ,
@@ -256,23 +357,29 @@ export default function RoomHeader({
256357 < Flex as = "header" align = "center" gap = "var(--cpd-space-3x)" className = "mx_RoomHeader light-panel" >
257358 < WithPresenceIndicator room = { room } size = "8px" >
258359 { /* We hide this from the tabIndex list as it is a pointer shortcut and superfluous for a11y */ }
360+ { /* Disable on-click actions until the room is created */ }
259361 < RoomAvatar
260362 room = { room }
261363 size = "40px"
262364 oobData = { oobData }
263- onClick = { onAvatarClick }
365+ onClick = { room instanceof LocalRoom ? undefined : onAvatarClick }
264366 tabIndex = { - 1 }
265367 aria-label = { _t ( "room|header_avatar_open_settings_label" ) }
266368 />
267369 </ WithPresenceIndicator >
370+ { /* Disable on-click actions until the room is created */ }
268371 < button
269372 aria-label = { _t ( "right_panel|room_summary_card|title" ) }
270373 tabIndex = { 0 }
271- onClick = { ( ) => RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . RoomSummary ) }
374+ onClick = {
375+ room instanceof LocalRoom
376+ ? undefined
377+ : ( ) => RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . RoomSummary )
378+ }
272379 className = "mx_RoomHeader_infoWrapper"
273380 >
274381 < Box flex = "1" className = "mx_RoomHeader_info" >
275- < BodyText
382+ < Text
276383 as = "div"
277384 size = "lg"
278385 weight = "semibold"
@@ -316,99 +423,12 @@ export default function RoomHeader({
316423 />
317424 </ Tooltip >
318425 ) }
319- </ BodyText >
426+ </ Text >
320427 </ Box >
321428 </ button >
322-
323- { additionalButtons ?. map ( ( props ) => {
324- const label = props . label ( ) ;
325-
326- return (
327- < Tooltip label = { label } key = { props . id } >
328- < IconButton
329- aria-label = { label }
330- onClick = { ( event ) => {
331- event . stopPropagation ( ) ;
332- props . onClick ( ) ;
333- } }
334- >
335- { typeof props . icon === "function" ? props . icon ( ) : props . icon }
336- </ IconButton >
337- </ Tooltip >
338- ) ;
339- } ) }
340-
341- { isViewingCall && < CallGuestLinkButton room = { room } /> }
342-
343- { hasActiveCallSession && ! isConnectedToCall && ! isViewingCall ? (
344- joinCallButton
345- ) : (
346- < >
347- { ! isVideoRoom && videoCallButton }
348- { ! useElementCallExclusively && ! isVideoRoom && voiceCallButton }
349- </ >
350- ) }
351-
352- { showChatButton && < VideoRoomChatButton room = { room } /> }
353-
354- < Tooltip label = { _t ( "common|threads" ) } >
355- < IconButton
356- indicator = { notificationLevelToIndicator ( threadNotifications ) }
357- onClick = { ( evt ) => {
358- evt . stopPropagation ( ) ;
359- RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . ThreadPanel ) ;
360- PosthogTrackers . trackInteraction ( "WebRoomHeaderButtonsThreadsButton" , evt ) ;
361- } }
362- aria-label = { _t ( "common|threads" ) }
363- >
364- < ToggleableIcon Icon = { ThreadsIcon } phase = { RightPanelPhases . ThreadPanel } />
365- </ IconButton >
366- </ Tooltip >
367- { notificationsEnabled && (
368- < Tooltip label = { _t ( "notifications|enable_prompt_toast_title" ) } >
369- < IconButton
370- indicator = { notificationLevelToIndicator ( globalNotificationState . level ) }
371- onClick = { ( evt ) => {
372- evt . stopPropagation ( ) ;
373- RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . NotificationPanel ) ;
374- } }
375- aria-label = { _t ( "notifications|enable_prompt_toast_title" ) }
376- >
377- < ToggleableIcon Icon = { NotificationsIcon } phase = { RightPanelPhases . NotificationPanel } />
378- </ IconButton >
379- </ Tooltip >
380- ) }
381-
382- < Tooltip label = { _t ( "right_panel|room_summary_card|title" ) } >
383- < IconButton
384- onClick = { ( evt ) => {
385- evt . stopPropagation ( ) ;
386- RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . RoomSummary ) ;
387- } }
388- aria-label = { _t ( "right_panel|room_summary_card|title" ) }
389- >
390- < ToggleableIcon Icon = { RoomInfoIcon } phase = { RightPanelPhases . RoomSummary } />
391- </ IconButton >
392- </ Tooltip >
393-
394- { ! isDirectMessage && (
395- < BodyText as = "div" size = "sm" weight = "medium" >
396- < FacePile
397- className = "mx_RoomHeader_members"
398- members = { members . slice ( 0 , 3 ) }
399- size = "20px"
400- overflow = { false }
401- viewUserOnClick = { false }
402- tooltipLabel = { _t ( "room|header_face_pile_tooltip" ) }
403- onClick = { ( e : ButtonEvent ) => {
404- RightPanelStore . instance . showOrHidePhase ( RightPanelPhases . MemberList ) ;
405- e . stopPropagation ( ) ;
406- } }
407- aria-label = { _t ( "common|n_members" , { count : memberCount } ) }
408- >
409- { formatCount ( memberCount ) }
410- </ FacePile >
411- </ BodyText >
429+ { /* If the room is local-only then we don't want to show any additional buttons, as it won't work */ }
430+ { room instanceof LocalRoom === false && (
431+ < RoomHeaderButtons room = { room } additionalButtons = { additionalButtons } />
412432 ) }
413433 </ Flex >
414434 { askToJoinEnabled && < RoomKnocksBar room = { room } /> }
0 commit comments