♻️(frontend) move InviteDialog state down the React tree

The InviteDialog open state was managed very high in the React tree,
which triggered a re-render of the whole conference tree whenever
the dialog was opened or closed.

Push the state down to a narrower component to limit the scope of
re-renders.

Part of a broader effort to isolate as much as possible what should
re-render, so we can then focus on tackling the real performance
issues.
This commit is contained in:
lebaudantoine
2026-07-13 19:17:04 +02:00
committed by aleb_the_flash
parent 63a7de402b
commit 8cd6496b5b
2 changed files with 137 additions and 144 deletions
@@ -170,7 +170,6 @@ export const Conference = ({
prepareConnection() prepareConnection()
}, [room, apiConfig, isConnectionWarmedUp]) }, [room, apiConfig, isConnectionWarmedUp])
const [showInviteDialog, setShowInviteDialog] = useState(mode === 'create')
const [mediaDeviceError, setMediaDeviceError] = useState<{ const [mediaDeviceError, setMediaDeviceError] = useState<{
error: MediaDeviceFailure | null error: MediaDeviceFailure | null
kind: MediaDeviceKind | null kind: MediaDeviceKind | null
@@ -303,13 +302,7 @@ export const Conference = ({
}} }}
> >
<VideoConference /> <VideoConference />
{showInviteDialog && !isMobile && ( {!isMobile && <InviteDialog mode={mode} />}
<InviteDialog
isOpen={showInviteDialog}
onOpenChange={setShowInviteDialog}
onClose={() => setShowInviteDialog(false)}
/>
)}
<MediaDeviceErrorAlert <MediaDeviceErrorAlert
{...mediaDeviceError} {...mediaDeviceError}
onClose={() => setMediaDeviceError({ error: null, kind: null })} onClose={() => setMediaDeviceError({ error: null, kind: null })}
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { getRouteUrl } from '@/navigation/getRouteUrl' import { getRouteUrl } from '@/navigation/getRouteUrl'
import { Div, Button, type DialogProps, P, Bold } from '@/primitives' import { Div, Button, P, Bold } from '@/primitives'
import { HStack, styled, VStack } from '@/styled-system/jsx' import { HStack, styled, VStack } from '@/styled-system/jsx'
import { Heading, Dialog } from 'react-aria-components' import { Heading, Dialog } from 'react-aria-components'
import { Text, text } from '@/primitives/Text' import { Text, text } from '@/primitives/Text'
@@ -10,7 +10,7 @@ import {
RiFileCopyLine, RiFileCopyLine,
RiSpam2Fill, RiSpam2Fill,
} from '@remixicon/react' } from '@remixicon/react'
import { useMemo } from 'react' import { useMemo, useState } from 'react'
import { css } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData' import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
import { ApiAccessLevel } from '@/features/rooms/api/ApiRoom' import { ApiAccessLevel } from '@/features/rooms/api/ApiRoom'
@@ -39,7 +39,9 @@ const StyledRACDialog = styled(Dialog, {
}, },
}) })
export const InviteDialog = (props: Omit<DialogProps, 'title'>) => { export const InviteDialog = ({ mode }: { mode: 'join' | 'create' }) => {
const [showInviteDialog, setShowInviteDialog] = useState(mode === 'create')
const { t } = useTranslation('rooms', { keyPrefix: 'shareDialog' }) const { t } = useTranslation('rooms', { keyPrefix: 'shareDialog' })
const roomData = useRoomData() const roomData = useRoomData()
@@ -58,163 +60,161 @@ export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
copyRoomUrlToClipboard, copyRoomUrlToClipboard,
} = useCopyRoomToClipboard(roomData) } = useCopyRoomToClipboard(roomData)
if (!showInviteDialog) return null
return ( return (
<StyledRACDialog {...props}> <StyledRACDialog>
{({ close }) => ( <VStack
<VStack alignItems="left"
alignItems="left" justify="start"
justify="start" gap={0}
gap={0} style={{ maxWidth: '100%', overflow: 'visible' }}
style={{ maxWidth: '100%', overflow: 'visible' }} >
> <Heading slot="title" level={2} className={text({ variant: 'h2' })}>
<Heading slot="title" level={2} className={text({ variant: 'h2' })}> {t('heading')}
{t('heading')} </Heading>
</Heading> <Div position="absolute" top="5" right="5">
<Div position="absolute" top="5" right="5"> <Button
<Button invisible
invisible variant="tertiaryText"
variant="tertiaryText" size="xs"
size="xs" onPress={() => {
onPress={() => { setShowInviteDialog(false)
props.onClose?.() }}
close() aria-label={t('closeDialog')}
}} >
aria-label={t('closeDialog')} <RiCloseLine />
> </Button>
<RiCloseLine /> </Div>
</Button> <P>{t('description')}</P>
</Div> {isTelephonyReadyForUse ? (
<P>{t('description')}</P> <div
{isTelephonyReadyForUse ? ( className={css({
width: '100%',
display: 'flex',
flexDirection: 'column',
marginTop: '0.5rem',
gap: '1rem',
overflow: 'visible',
})}
>
<div <div
className={css({ className={css({
width: '100%',
display: 'flex', display: 'flex',
flexDirection: 'column', alignItems: 'center',
marginTop: '0.5rem', justifyContent: 'space-between',
gap: '1rem',
overflow: 'visible',
})} })}
> >
<div <Text as="p" wrap="pretty">
className={css({ {roomUrl?.replace(/^https?:\/\//, '')}
display: 'flex', </Text>
alignItems: 'center', {isTelephonyReadyForUse && roomUrl && (
justifyContent: 'space-between', <Button
})} variant={isRoomUrlCopied ? 'success' : 'tertiaryText'}
> square
<Text as="p" wrap="pretty"> size={'sm'}
{roomUrl?.replace(/^https?:\/\//, '')} onPress={copyRoomUrlToClipboard}
</Text> aria-label={isRoomUrlCopied ? t('copied') : t('copyUrl')}
{isTelephonyReadyForUse && roomUrl && ( tooltip={isRoomUrlCopied ? t('copied') : t('copyUrl')}
<Button >
variant={isRoomUrlCopied ? 'success' : 'tertiaryText'} {isRoomUrlCopied ? (
square <RiCheckLine aria-hidden="true" />
size={'sm'} ) : (
onPress={copyRoomUrlToClipboard} <RiFileCopyLine aria-hidden="true" />
aria-label={isRoomUrlCopied ? t('copied') : t('copyUrl')} )}
tooltip={isRoomUrlCopied ? t('copied') : t('copyUrl')} </Button>
> )}
{isRoomUrlCopied ? (
<RiCheckLine aria-hidden="true" />
) : (
<RiFileCopyLine aria-hidden="true" />
)}
</Button>
)}
</div>
<div
className={css({
display: 'flex',
flexDirection: 'column',
})}
>
<Text as="p" wrap="pretty">
<Bold>{t('phone.call')}</Bold> ({telephony?.country}){' '}
{telephony?.internationalPhoneNumber}
</Text>
<Text as="p" wrap="pretty">
<Bold>{t('phone.pinCode')}</Bold>{' '}
{formatPinCode(roomData?.pin_code)}
</Text>
</div>
<Button
variant={isCopied ? 'success' : 'secondaryText'}
size="sm"
fullWidth
aria-label={isCopied ? t('copied') : t('copy')}
style={{
justifyContent: 'start',
}}
onPress={copyRoomToClipboard}
data-attr="share-dialog-copy"
>
{isCopied ? (
<>
<RiCheckLine
size={18}
style={{ marginRight: '8px' }}
aria-hidden="true"
/>
{t('copied')}
</>
) : (
<>
<RiFileCopyLine
style={{ marginRight: '6px', minWidth: '18px' }}
aria-hidden="true"
/>
{t('copy')}
</>
)}
</Button>
</div> </div>
) : ( <div
className={css({
display: 'flex',
flexDirection: 'column',
})}
>
<Text as="p" wrap="pretty">
<Bold>{t('phone.call')}</Bold> ({telephony?.country}){' '}
{telephony?.internationalPhoneNumber}
</Text>
<Text as="p" wrap="pretty">
<Bold>{t('phone.pinCode')}</Bold>{' '}
{formatPinCode(roomData?.pin_code)}
</Text>
</div>
<Button <Button
variant={isCopied ? 'success' : 'tertiary'} variant={isCopied ? 'success' : 'secondaryText'}
size="sm"
fullWidth fullWidth
aria-label={isCopied ? t('copied') : t('copy')} aria-label={isCopied ? t('copied') : t('copy')}
style={{
justifyContent: 'start',
}}
onPress={copyRoomToClipboard} onPress={copyRoomToClipboard}
data-attr="share-dialog-copy" data-attr="share-dialog-copy"
> >
{isCopied ? ( {isCopied ? (
<> <>
<RiCheckLine size={24} style={{ marginRight: '8px' }} /> <RiCheckLine
size={18}
style={{ marginRight: '8px' }}
aria-hidden="true"
/>
{t('copied')} {t('copied')}
</> </>
) : ( ) : (
<> <>
<RiFileCopyLine size={24} style={{ marginRight: '8px' }} /> <RiFileCopyLine
{t('copyUrl')} style={{ marginRight: '6px', minWidth: '18px' }}
aria-hidden="true"
/>
{t('copy')}
</> </>
)} )}
</Button> </Button>
)} </div>
{roomData?.access_level === ApiAccessLevel.PUBLIC && ( ) : (
<HStack> <Button
<div variant={isCopied ? 'success' : 'tertiary'}
fullWidth
aria-label={isCopied ? t('copied') : t('copy')}
onPress={copyRoomToClipboard}
data-attr="share-dialog-copy"
>
{isCopied ? (
<>
<RiCheckLine size={24} style={{ marginRight: '8px' }} />
{t('copied')}
</>
) : (
<>
<RiFileCopyLine size={24} style={{ marginRight: '8px' }} />
{t('copyUrl')}
</>
)}
</Button>
)}
{roomData?.access_level === ApiAccessLevel.PUBLIC && (
<HStack>
<div
className={css({
backgroundColor: 'primary.200',
borderRadius: '50%',
padding: '4px',
marginTop: '1rem',
})}
>
<RiSpam2Fill
size={22}
className={css({ className={css({
backgroundColor: 'primary.200', fill: 'primary.500',
borderRadius: '50%',
padding: '4px',
marginTop: '1rem',
})} })}
> />
<RiSpam2Fill </div>
size={22} <Text variant="sm" style={{ marginTop: '1rem' }}>
className={css({ {t('permissions')}
fill: 'primary.500', </Text>
})} </HStack>
/> )}
</div> </VStack>
<Text variant="sm" style={{ marginTop: '1rem' }}>
{t('permissions')}
</Text>
</HStack>
)}
</VStack>
)}
</StyledRACDialog> </StyledRACDialog>
) )
} }