🚸(frontend) avoid blocking user with invitation dialog

Removed annoying overlay that blocked the user. (feedback from @spaccoud)

Previous design required one click too many. As this dialog doesn't need
an overlay, I couldn't use the default primitive.

It's a hacky but functional, creating technical debt here.

Closer to the Gmeet design. Added a warning about permissions
since the rooms are public in beta.

Apologies @manuhabitela, this may impact accessibility for  users unfamiliar
with the copy icon. Let's conduct user testing.
This commit is contained in:
lebaudantoine
2024-08-30 11:06:14 +02:00
committed by aleb_the_flash
parent e06e9d1496
commit 11e162dbd4
4 changed files with 109 additions and 52 deletions

View File

@@ -1,8 +1,31 @@
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { getRouteUrl } from '@/navigation/getRouteUrl' import { getRouteUrl } from '@/navigation/getRouteUrl'
import { Div, Button, Dialog, Input, type DialogProps } from '@/primitives' import { Div, Button, type DialogProps, P } from '@/primitives'
import { HStack } from '@/styled-system/jsx' import { HStack, styled, VStack } from '@/styled-system/jsx'
import { Heading, Dialog } from 'react-aria-components'
import { Text, text } from '@/primitives/Text'
import { RiCloseLine, RiFileCopyLine, RiSpam2Fill } from '@remixicon/react'
// fixme - extract in a proper primitive this dialog without overlay
const StyledRACDialog = styled(Dialog, {
base: {
position: 'fixed',
left: 30,
bottom: 90,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000,
width: '24.5rem',
borderRadius: '8px',
padding: '1.5rem',
boxShadow:
'0 1px 2px 0 rgba(60, 64, 67, .3), 0 2px 6px 2px rgba(60, 64, 67, .15)',
backgroundColor: 'white',
'&[data-entering]': { animation: 'fade 200ms' },
'&[data-exiting]': { animation: 'fade 150ms reverse ease-in' },
},
})
export const InviteDialog = ({ export const InviteDialog = ({
roomId, roomId,
@@ -11,48 +34,82 @@ export const InviteDialog = ({
const { t } = useTranslation('rooms') const { t } = useTranslation('rooms')
const roomUrl = getRouteUrl('room', roomId) const roomUrl = getRouteUrl('room', roomId)
const copyLabel = t('shareDialog.copy')
const copiedLabel = t('shareDialog.copied')
const [copyLinkLabel, setCopyLinkLabel] = useState(copyLabel)
useEffect(() => {
if (copyLinkLabel == copiedLabel) {
const timeout = setTimeout(() => {
setCopyLinkLabel(copyLabel)
}, 5000)
return () => {
clearTimeout(timeout)
}
}
}, [copyLinkLabel, copyLabel, copiedLabel])
return ( return (
<Dialog {...dialogProps} title={t('shareDialog.heading')}> <StyledRACDialog {...dialogProps}>
<HStack alignItems="stretch" gap="gutter"> {({ close }) => (
<Div flex="1"> <VStack
<Input alignItems={'left'}
type="text" justify="start"
aria-label={t('shareDialog.inputLabel')} gap={0}
value={roomUrl} style={{
readOnly maxWidth: '100%',
onClick={(e) => { overflow: 'hidden',
e.currentTarget.select() }}
}} >
/> <Heading slot="title" level={3} className={text({ variant: 'h2' })}>
</Div> {t('shareDialog.heading')}
<Div minWidth="8rem"> </Heading>
<Button <Div position="absolute" top="5" right="5">
variant="primary" <Button
size="sm" invisible
fullWidth size="xs"
onPress={() => { onPress={() => {
navigator.clipboard.writeText(roomUrl) dialogProps.onClose?.()
setCopyLinkLabel(copiedLabel) close()
}}
aria-label={t('closeDialog')}
>
<RiCloseLine />
</Button>
</Div>
<P>{t('shareDialog.description')}</P>
<HStack
justify={'space-between'}
alignItems="center"
style={{
backgroundColor: '#f1f3f4',
borderRadius: '4px',
maxWidth: '100%',
}} }}
gap={0}
> >
{copyLinkLabel} <div
</Button> style={{
</Div> paddingLeft: '0.75rem',
</HStack> textOverflow: 'ellipsis',
</Dialog> overflow: 'hidden',
textWrap: 'nowrap',
userSelect: 'none',
}}
>
{roomUrl.replace(/^https?:\/\//, '')}
</div>
<Button
square
invisible
tooltip={t('shareDialog.copy')}
onPress={() => navigator.clipboard.writeText(roomUrl)}
>
<RiFileCopyLine size={24} />
</Button>
</HStack>
<HStack>
<div
style={{
backgroundColor: '#d9e5ff',
borderRadius: '50%',
padding: '4px',
marginTop: '1rem',
}}
>
<RiSpam2Fill size={22} style={{ fill: '#4c84fc' }} />
</div>
<Text variant="sm" style={{ marginTop: '1rem' }}>
{t('shareDialog.permissions')}
</Text>
</HStack>
</VStack>
)}
</StyledRACDialog>
) )
} }

View File

@@ -12,10 +12,10 @@
}, },
"leaveRoomPrompt": "", "leaveRoomPrompt": "",
"shareDialog": { "shareDialog": {
"copied": "",
"copy": "", "copy": "",
"heading": "", "heading": "",
"inputLabel": "" "description": "",
"permissions": ""
}, },
"error": { "error": {
"createRoom": { "createRoom": {

View File

@@ -12,10 +12,10 @@
}, },
"leaveRoomPrompt": "This will make you leave the meeting.", "leaveRoomPrompt": "This will make you leave the meeting.",
"shareDialog": { "shareDialog": {
"copied": "Copied", "copy": "Copy link",
"copy": "Copy", "heading": "Your meeting is ready",
"heading": "Share the meeting link", "description": "Share this link with people you want to invite to the meeting.",
"inputLabel": "Meeting link" "permissions": "People with this link do not need your permission to join this meeting."
}, },
"error": { "error": {
"createRoom": { "createRoom": {

View File

@@ -12,10 +12,10 @@
}, },
"leaveRoomPrompt": "Revenir à l'accueil vous fera quitter la réunion.", "leaveRoomPrompt": "Revenir à l'accueil vous fera quitter la réunion.",
"shareDialog": { "shareDialog": {
"copied": "Lien copié",
"copy": "Copier le lien", "copy": "Copier le lien",
"heading": "Partager le lien vers la réunion", "heading": "Votre réunion est prête",
"inputLabel": "Lien vers la réunion" "description": "Partagez ce lien avec les personnes que vous souhaitez inviter à la réunion.",
"permissions": "Les personnes disposant de ce lien n'ont pas besoin de votre autorisation pour rejoindre cette réunion."
}, },
"error": { "error": {
"createRoom": { "createRoom": {