✨(frontend) allow local participant to update her name
The user name is initially set by the backend when generating the LiveKit access token. By default, if the frontend has not provided a username, the backend uses the user's email address. This approach isn't ideal, as some users prefer using their first name. This update allows local participant to change their username in real-time during a session. However, these changes are not yet persisted for future meetings. This persistence feature will be added in upcoming commits.
This commit is contained in:
committed by
aleb_the_flash
parent
fe8ed43aae
commit
37eea16a50
@@ -3,6 +3,7 @@ import {
|
|||||||
RiFeedbackLine,
|
RiFeedbackLine,
|
||||||
RiQuestionLine,
|
RiQuestionLine,
|
||||||
RiSettings3Line,
|
RiSettings3Line,
|
||||||
|
RiUser5Line,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { styled } from '@/styled-system/jsx'
|
import { styled } from '@/styled-system/jsx'
|
||||||
@@ -10,8 +11,10 @@ import {
|
|||||||
Menu as RACMenu,
|
Menu as RACMenu,
|
||||||
MenuItem as RACMenuItem,
|
MenuItem as RACMenuItem,
|
||||||
Popover as RACPopover,
|
Popover as RACPopover,
|
||||||
|
Separator as RACSeparator,
|
||||||
} from 'react-aria-components'
|
} from 'react-aria-components'
|
||||||
import { SettingsDialog } from '@/features/settings'
|
import { SettingsDialog } from '@/features/settings'
|
||||||
|
import { UsernameDialog } from '../../dialogs/UsernameDialog'
|
||||||
|
|
||||||
// Styled components to be refactored
|
// Styled components to be refactored
|
||||||
const StyledMenu = styled(RACMenu, {
|
const StyledMenu = styled(RACMenu, {
|
||||||
@@ -60,13 +63,28 @@ const StyledPopover = styled(RACPopover, {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const StyledSeparator = styled(RACSeparator, {
|
||||||
|
base: {
|
||||||
|
height: '1px',
|
||||||
|
background: '#9ca3af',
|
||||||
|
margin: '2px 4px',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
type DialogState = 'username' | 'settings' | null
|
||||||
|
|
||||||
export const OptionsMenu = () => {
|
export const OptionsMenu = () => {
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
const [isSettingsDialogOpen, setIsSettingsDialogOpen] = useState(false)
|
const [dialogOpen, setDialogOpen] = useState<DialogState>(null)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledPopover>
|
<StyledPopover>
|
||||||
<StyledMenu>
|
<StyledMenu>
|
||||||
|
<StyledMenuItem onAction={() => setDialogOpen('username')}>
|
||||||
|
<RiUser5Line size={18} />
|
||||||
|
{t('options.items.username')}
|
||||||
|
</StyledMenuItem>
|
||||||
|
<StyledSeparator />
|
||||||
<StyledMenuItem
|
<StyledMenuItem
|
||||||
href="https://tchap.gouv.fr/#/room/!aGImQayAgBLjSBycpm:agent.dinum.tchap.gouv.fr?via=agent.dinum.tchap.gouv.fr"
|
href="https://tchap.gouv.fr/#/room/!aGImQayAgBLjSBycpm:agent.dinum.tchap.gouv.fr?via=agent.dinum.tchap.gouv.fr"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -81,15 +99,19 @@ export const OptionsMenu = () => {
|
|||||||
<RiFeedbackLine size={18} />
|
<RiFeedbackLine size={18} />
|
||||||
{t('options.items.feedbacks')}
|
{t('options.items.feedbacks')}
|
||||||
</StyledMenuItem>
|
</StyledMenuItem>
|
||||||
<StyledMenuItem onAction={() => setIsSettingsDialogOpen(true)}>
|
<StyledMenuItem onAction={() => setDialogOpen('settings')}>
|
||||||
<RiSettings3Line size={18} />
|
<RiSettings3Line size={18} />
|
||||||
{t('options.items.settings')}
|
{t('options.items.settings')}
|
||||||
</StyledMenuItem>
|
</StyledMenuItem>
|
||||||
</StyledMenu>
|
</StyledMenu>
|
||||||
</StyledPopover>
|
</StyledPopover>
|
||||||
|
<UsernameDialog
|
||||||
|
isOpen={dialogOpen === 'username'}
|
||||||
|
onOpenChange={(v) => !v && setDialogOpen(null)}
|
||||||
|
/>
|
||||||
<SettingsDialog
|
<SettingsDialog
|
||||||
isOpen={isSettingsDialogOpen}
|
isOpen={dialogOpen === 'settings'}
|
||||||
onOpenChange={(v) => setIsSettingsDialogOpen(v)}
|
onOpenChange={(v) => !v && setDialogOpen(null)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { Field, Form, Dialog, DialogProps } from '@/primitives'
|
||||||
|
import { useRoomContext } from '@livekit/components-react'
|
||||||
|
|
||||||
|
export type UsernameDialogProps = Pick<DialogProps, 'isOpen' | 'onOpenChange'>
|
||||||
|
|
||||||
|
export const UsernameDialog = (props: UsernameDialogProps) => {
|
||||||
|
const { t } = useTranslation('rooms')
|
||||||
|
|
||||||
|
const ctx = useRoomContext()
|
||||||
|
return (
|
||||||
|
<Dialog title={t('options.username.heading')} {...props}>
|
||||||
|
<Form
|
||||||
|
onSubmit={(data) => {
|
||||||
|
ctx.localParticipant.setName(data.username as string)
|
||||||
|
const { onOpenChange } = props
|
||||||
|
if (onOpenChange) {
|
||||||
|
onOpenChange(false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
submitLabel={t('options.username.submitLabel')}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
name="username"
|
||||||
|
label={t('options.username.label')}
|
||||||
|
description={t('options.username.description')}
|
||||||
|
defaultValue={ctx.localParticipant.name}
|
||||||
|
validate={(value) => {
|
||||||
|
return !value ? (
|
||||||
|
<p>{t('options.username.validationError')}</p>
|
||||||
|
) : null
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -36,7 +36,15 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"feedbacks": "",
|
"feedbacks": "",
|
||||||
"support": "",
|
"support": "",
|
||||||
"settings": ""
|
"settings": "",
|
||||||
|
"username": ""
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"heading": "",
|
||||||
|
"label": "",
|
||||||
|
"description": "",
|
||||||
|
"validationError": "",
|
||||||
|
"submitLabel": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,15 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"feedbacks": "Give us feedbacks",
|
"feedbacks": "Give us feedbacks",
|
||||||
"support": "Get Help on Tchap",
|
"support": "Get Help on Tchap",
|
||||||
"settings": "Settings"
|
"settings": "Settings",
|
||||||
|
"username": "Update Your Name"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"heading": "Update Your Name",
|
||||||
|
"label": "Your Name",
|
||||||
|
"description": "All other participants will see this name.",
|
||||||
|
"validationError": "Name cannot be empty.",
|
||||||
|
"submitLabel": "Save"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,15 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"feedbacks": "Partager votre avis",
|
"feedbacks": "Partager votre avis",
|
||||||
"support": "Obtenir de l'aide sur Tchap",
|
"support": "Obtenir de l'aide sur Tchap",
|
||||||
"settings": "Paramètres"
|
"settings": "Paramètres",
|
||||||
|
"username": "Choisir votre nom"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"heading": "Choisir votre nom",
|
||||||
|
"label": "Votre Nom",
|
||||||
|
"description": "Tous les autres participants verront ce nom.",
|
||||||
|
"validationError": "Le nom ne peut pas être vide.",
|
||||||
|
"submitLabel": "Enregistrer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user