♻️(frontend) move name update to AccountTab
User can now update their name in a dedicated Account tab, inspired by Jitsi design. Removed the username dialog. Account-related updates will be operated through the advanced settings dialog, in this dedicated tab.
This commit is contained in:
committed by
aleb_the_flash
parent
6a7ec95493
commit
12c27eedac
@@ -3,7 +3,6 @@ import { RiMore2Line } from '@remixicon/react'
|
|||||||
import { Button, Menu } from '@/primitives'
|
import { Button, Menu } from '@/primitives'
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { UsernameDialog } from '@/features/rooms/livekit/components/dialogs/UsernameDialog'
|
|
||||||
import { OptionsMenuItems } from '@/features/rooms/livekit/components/controls/Options/OptionsMenuItems'
|
import { OptionsMenuItems } from '@/features/rooms/livekit/components/controls/Options/OptionsMenuItems'
|
||||||
import { SettingsDialogExtended } from '@/features/settings/components/SettingsDialogExtended'
|
import { SettingsDialogExtended } from '@/features/settings/components/SettingsDialogExtended'
|
||||||
|
|
||||||
@@ -25,10 +24,6 @@ export const OptionsButton = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
<OptionsMenuItems onOpenDialog={setDialogOpen} />
|
<OptionsMenuItems onOpenDialog={setDialogOpen} />
|
||||||
</Menu>
|
</Menu>
|
||||||
<UsernameDialog
|
|
||||||
isOpen={dialogOpen === 'username'}
|
|
||||||
onOpenChange={(v) => !v && setDialogOpen(null)}
|
|
||||||
/>
|
|
||||||
<SettingsDialogExtended
|
<SettingsDialogExtended
|
||||||
isOpen={dialogOpen === 'settings'}
|
isOpen={dialogOpen === 'settings'}
|
||||||
onOpenChange={(v) => !v && setDialogOpen(null)}
|
onOpenChange={(v) => !v && setDialogOpen(null)}
|
||||||
|
|||||||
@@ -3,26 +3,12 @@ import {
|
|||||||
RiFeedbackLine,
|
RiFeedbackLine,
|
||||||
RiQuestionLine,
|
RiQuestionLine,
|
||||||
RiSettings3Line,
|
RiSettings3Line,
|
||||||
RiUser5Line,
|
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { styled } from '@/styled-system/jsx'
|
import { MenuItem, Menu as RACMenu } from 'react-aria-components'
|
||||||
import {
|
|
||||||
MenuItem,
|
|
||||||
Menu as RACMenu,
|
|
||||||
Separator as RACSeparator,
|
|
||||||
} from 'react-aria-components'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Dispatch, SetStateAction } from 'react'
|
import { Dispatch, SetStateAction } from 'react'
|
||||||
import { DialogState } from '@/features/rooms/livekit/components/controls/Options/OptionsButton'
|
import { DialogState } from '@/features/rooms/livekit/components/controls/Options/OptionsButton'
|
||||||
|
|
||||||
const StyledSeparator = styled(RACSeparator, {
|
|
||||||
base: {
|
|
||||||
height: '1px',
|
|
||||||
background: 'gray.300',
|
|
||||||
margin: '4px 0',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// @todo try refactoring it to use MenuList component
|
// @todo try refactoring it to use MenuList component
|
||||||
export const OptionsMenuItems = ({
|
export const OptionsMenuItems = ({
|
||||||
onOpenDialog,
|
onOpenDialog,
|
||||||
@@ -38,14 +24,6 @@ export const OptionsMenuItems = ({
|
|||||||
width: '300px',
|
width: '300px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem
|
|
||||||
className={menuItemRecipe({ icon: true })}
|
|
||||||
onAction={() => onOpenDialog('username')}
|
|
||||||
>
|
|
||||||
<RiUser5Line size={18} />
|
|
||||||
{t('options.items.username')}
|
|
||||||
</MenuItem>
|
|
||||||
<StyledSeparator />
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
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"
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import { Field, Form, Dialog, DialogProps } from '@/primitives'
|
|
||||||
import {
|
|
||||||
usePersistentUserChoices,
|
|
||||||
useRoomContext,
|
|
||||||
} from '@livekit/components-react'
|
|
||||||
|
|
||||||
export type UsernameDialogProps = Pick<DialogProps, 'isOpen' | 'onOpenChange'>
|
|
||||||
|
|
||||||
export const UsernameDialog = (props: UsernameDialogProps) => {
|
|
||||||
const { t } = useTranslation('rooms')
|
|
||||||
const { saveUsername } = usePersistentUserChoices()
|
|
||||||
|
|
||||||
const ctx = useRoomContext()
|
|
||||||
return (
|
|
||||||
<Dialog title={t('options.username.heading')} {...props}>
|
|
||||||
<Form
|
|
||||||
onSubmit={(data) => {
|
|
||||||
const { username } = data as { username: string }
|
|
||||||
ctx.localParticipant.setName(username)
|
|
||||||
saveUsername(username)
|
|
||||||
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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
RiSettings3Line,
|
RiSettings3Line,
|
||||||
RiSpeakerLine,
|
RiSpeakerLine,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
|
import { AccountTab } from './tabs/AccountTab'
|
||||||
|
|
||||||
const tabsStyle = css({
|
const tabsStyle = css({
|
||||||
maxHeight: '40.625rem', // fixme size copied from meet settings modal
|
maxHeight: '40.625rem', // fixme size copied from meet settings modal
|
||||||
@@ -65,9 +66,7 @@ export const SettingsDialogExtended = (props: SettingsDialogExtended) => {
|
|||||||
</TabList>
|
</TabList>
|
||||||
</div>
|
</div>
|
||||||
<div className={tabPanelContainerStyle}>
|
<div className={tabPanelContainerStyle}>
|
||||||
<TabPanel flex id="1">
|
<AccountTab id="1" onOpenChange={props.onOpenChange} />
|
||||||
There are your profile settings
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel flex id="2">
|
<TabPanel flex id="2">
|
||||||
There are your audio settings
|
There are your audio settings
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { A, Badge, Button, DialogProps, Field, H, P } from '@/primitives'
|
||||||
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
|
import {
|
||||||
|
usePersistentUserChoices,
|
||||||
|
useRoomContext,
|
||||||
|
} from '@livekit/components-react'
|
||||||
|
import { authUrl, logoutUrl, useUser } from '@/features/auth'
|
||||||
|
import { css } from '@/styled-system/css'
|
||||||
|
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||||
|
import { HStack } from '@/styled-system/jsx'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||||
|
Pick<TabPanelProps, 'id'>
|
||||||
|
|
||||||
|
export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
|
||||||
|
const { t } = useTranslation('settings')
|
||||||
|
const { saveUsername } = usePersistentUserChoices()
|
||||||
|
const room = useRoomContext()
|
||||||
|
const { user, isLoggedIn } = useUser()
|
||||||
|
const [name, setName] = useState(room?.localParticipant.name || '')
|
||||||
|
|
||||||
|
const handleOnSubmit = () => {
|
||||||
|
if (room) room.localParticipant.setName(name)
|
||||||
|
saveUsername(name)
|
||||||
|
if (onOpenChange) onOpenChange(false)
|
||||||
|
}
|
||||||
|
const handleOnCancel = () => {
|
||||||
|
if (onOpenChange) onOpenChange(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TabPanel padding={'md'} flex id={id}>
|
||||||
|
<H lvl={2}>{t('account.heading')}</H>
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
label={t('account.nameLabel')}
|
||||||
|
value={name}
|
||||||
|
onChange={setName}
|
||||||
|
validate={(value) => {
|
||||||
|
return !value ? <p>{'Votre Nom ne peut pas être vide'}</p> : null
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<H lvl={2}>{t('account.authentication')}</H>
|
||||||
|
{isLoggedIn ? (
|
||||||
|
<>
|
||||||
|
<P>
|
||||||
|
<Trans
|
||||||
|
i18nKey="settings:account.currentlyLoggedAs"
|
||||||
|
values={{ user: user?.email }}
|
||||||
|
components={[<Badge />]}
|
||||||
|
/>
|
||||||
|
</P>
|
||||||
|
<P>
|
||||||
|
<A href={logoutUrl()}>{t('logout', { ns: 'global' })}</A>
|
||||||
|
</P>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<P>{t('account.youAreNotLoggedIn')}</P>
|
||||||
|
<P>
|
||||||
|
<A href={authUrl()}>{t('login', { ns: 'global' })}</A>
|
||||||
|
</P>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<HStack
|
||||||
|
className={css({
|
||||||
|
marginTop: 'auto',
|
||||||
|
marginLeft: 'auto',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button onPress={handleOnCancel}>
|
||||||
|
{t('cancel', { ns: 'global' })}
|
||||||
|
</Button>
|
||||||
|
<Button variant={'primary'} onPress={handleOnSubmit}>
|
||||||
|
{t('submit', { ns: 'global' })}
|
||||||
|
</Button>
|
||||||
|
</HStack>
|
||||||
|
</TabPanel>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
"logout": "",
|
"logout": "",
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
}
|
},
|
||||||
|
"submit": "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,13 +45,6 @@
|
|||||||
"support": "",
|
"support": "",
|
||||||
"settings": "",
|
"settings": "",
|
||||||
"username": ""
|
"username": ""
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"heading": "",
|
|
||||||
"label": "",
|
|
||||||
"description": "",
|
|
||||||
"validationError": "",
|
|
||||||
"submitLabel": ""
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participants": {
|
"participants": {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
"account": {
|
"account": {
|
||||||
"currentlyLoggedAs": "",
|
"currentlyLoggedAs": "",
|
||||||
"heading": "",
|
"heading": "",
|
||||||
"youAreNotLoggedIn": ""
|
"youAreNotLoggedIn": "",
|
||||||
|
"nameLabel": "",
|
||||||
|
"authentication": ""
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
|
|||||||
@@ -16,5 +16,6 @@
|
|||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"heading": "Page not found"
|
"heading": "Page not found"
|
||||||
}
|
},
|
||||||
|
"submit": "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,13 +45,6 @@
|
|||||||
"support": "Get Help on Tchap",
|
"support": "Get Help on Tchap",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"username": "Update Your Name"
|
"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"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participants": {
|
"participants": {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
"account": {
|
"account": {
|
||||||
"currentlyLoggedAs": "You are currently logged in as <0>{{user}}</0>",
|
"currentlyLoggedAs": "You are currently logged in as <0>{{user}}</0>",
|
||||||
"heading": "Account",
|
"heading": "Account",
|
||||||
"youAreNotLoggedIn": "You are not logged in."
|
"youAreNotLoggedIn": "You are not logged in.",
|
||||||
|
"nameLabel": "Votre Nom",
|
||||||
|
"authentication": "Authentication"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"heading": "Settings"
|
"heading": "Settings"
|
||||||
|
|||||||
@@ -16,5 +16,6 @@
|
|||||||
"logout": "Se déconnecter",
|
"logout": "Se déconnecter",
|
||||||
"notFound": {
|
"notFound": {
|
||||||
"heading": "Page introuvable"
|
"heading": "Page introuvable"
|
||||||
}
|
},
|
||||||
|
"submit": "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,13 +45,6 @@
|
|||||||
"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": "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"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participants": {
|
"participants": {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
"account": {
|
"account": {
|
||||||
"currentlyLoggedAs": "Vous êtes actuellement connecté en tant que <0>{{user}}</0>",
|
"currentlyLoggedAs": "Vous êtes actuellement connecté en tant que <0>{{user}}</0>",
|
||||||
"heading": "Compte",
|
"heading": "Compte",
|
||||||
"youAreNotLoggedIn": "Vous n'êtes pas connecté."
|
"youAreNotLoggedIn": "Vous n'êtes pas connecté.",
|
||||||
|
"nameLabel": "Votre Nom",
|
||||||
|
"authentication": "Authentification"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"heading": "Paramètres"
|
"heading": "Paramètres"
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ const StyledTabPanel = styled(RACTabPanel, {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
|
flexDirection: 'column', //fixme should be parameterizable
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
padding: {
|
padding: {
|
||||||
|
|||||||
Reference in New Issue
Block a user