✨(frontend) add telephony info to encourage phone participation
Add telephony information to the share dialog when available to help users take advantage of the newly introduced phone join feature. Promotes phone participation as an alternative connection method when users need it, improving meeting accessibility and user adoption of telephony capabilities.
This commit is contained in:
committed by
aleb_the_flash
parent
de3a5aa404
commit
f3af637fd6
@@ -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 } from '@/primitives'
|
import { Div, Button, type DialogProps, 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,10 +10,12 @@ import {
|
|||||||
RiFileCopyLine,
|
RiFileCopyLine,
|
||||||
RiSpam2Fill,
|
RiSpam2Fill,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, 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'
|
||||||
|
import { useTelephony } from '@/features/rooms/livekit/hooks/useTelephony'
|
||||||
|
import { formatPinCode } from '@/features/rooms/utils/telephony'
|
||||||
|
|
||||||
// fixme - extract in a proper primitive this dialog without overlay
|
// fixme - extract in a proper primitive this dialog without overlay
|
||||||
const StyledRACDialog = styled(Dialog, {
|
const StyledRACDialog = styled(Dialog, {
|
||||||
@@ -37,11 +39,12 @@ const StyledRACDialog = styled(Dialog, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
|
export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms', { keyPrefix: 'shareDialog' })
|
||||||
|
|
||||||
const roomData = useRoomData()
|
const roomData = useRoomData()
|
||||||
const roomUrl = getRouteUrl('room', roomData?.slug)
|
const roomUrl = getRouteUrl('room', roomData?.slug)
|
||||||
const [isCopied, setIsCopied] = useState(false)
|
const [isCopied, setIsCopied] = useState(false)
|
||||||
|
const [isRoomUrlCopied, setIsRoomUrlCopied] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCopied) {
|
if (isCopied) {
|
||||||
@@ -50,6 +53,38 @@ export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
|
|||||||
}
|
}
|
||||||
}, [isCopied])
|
}, [isCopied])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isRoomUrlCopied) {
|
||||||
|
const timeout = setTimeout(() => setIsRoomUrlCopied(false), 3000)
|
||||||
|
return () => clearTimeout(timeout)
|
||||||
|
}
|
||||||
|
}, [isRoomUrlCopied])
|
||||||
|
|
||||||
|
const telephony = useTelephony()
|
||||||
|
|
||||||
|
const isTelephonyReadyForUse = useMemo(() => {
|
||||||
|
return telephony?.enabled && roomData?.pin_code
|
||||||
|
}, [telephony?.enabled, roomData?.pin_code])
|
||||||
|
|
||||||
|
const clipboardContent = useMemo(() => {
|
||||||
|
if (isTelephonyReadyForUse) {
|
||||||
|
return [
|
||||||
|
t('clipboard.url', { roomUrl }),
|
||||||
|
t('clipboard.numberAndPin', {
|
||||||
|
phoneNumber: telephony?.internationalPhoneNumber,
|
||||||
|
pinCode: formatPinCode(roomData?.pin_code),
|
||||||
|
}),
|
||||||
|
].join('\n')
|
||||||
|
}
|
||||||
|
return roomUrl
|
||||||
|
}, [
|
||||||
|
isTelephonyReadyForUse,
|
||||||
|
roomUrl,
|
||||||
|
telephony?.internationalPhoneNumber,
|
||||||
|
roomData?.pin_code,
|
||||||
|
t,
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledRACDialog {...props}>
|
<StyledRACDialog {...props}>
|
||||||
{({ close }) => (
|
{({ close }) => (
|
||||||
@@ -60,7 +95,7 @@ export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
|
|||||||
style={{ maxWidth: '100%', overflow: 'hidden' }}
|
style={{ maxWidth: '100%', overflow: 'hidden' }}
|
||||||
>
|
>
|
||||||
<Heading slot="title" level={3} className={text({ variant: 'h2' })}>
|
<Heading slot="title" level={3} className={text({ variant: 'h2' })}>
|
||||||
{t('shareDialog.heading')}
|
{t('heading')}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Div position="absolute" top="5" right="5">
|
<Div position="absolute" top="5" right="5">
|
||||||
<Button
|
<Button
|
||||||
@@ -76,29 +111,114 @@ export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
|
|||||||
<RiCloseLine />
|
<RiCloseLine />
|
||||||
</Button>
|
</Button>
|
||||||
</Div>
|
</Div>
|
||||||
<P>{t('shareDialog.description')}</P>
|
<P>{t('description')}</P>
|
||||||
<Button
|
{isTelephonyReadyForUse ? (
|
||||||
variant={isCopied ? 'success' : 'tertiary'}
|
<div
|
||||||
fullWidth
|
className={css({
|
||||||
aria-label={t('shareDialog.copy')}
|
width: '100%',
|
||||||
onPress={() => {
|
display: 'flex',
|
||||||
navigator.clipboard.writeText(roomUrl)
|
flexDirection: 'column',
|
||||||
setIsCopied(true)
|
marginTop: '0.5rem',
|
||||||
}}
|
gap: '1rem',
|
||||||
data-attr="share-dialog-copy"
|
overflow: 'hidden',
|
||||||
>
|
})}
|
||||||
{isCopied ? (
|
>
|
||||||
<>
|
<div
|
||||||
<RiCheckLine size={24} style={{ marginRight: '8px' }} />
|
className={css({
|
||||||
{t('shareDialog.copied')}
|
display: 'flex',
|
||||||
</>
|
alignItems: 'center',
|
||||||
) : (
|
justifyContent: 'space-between',
|
||||||
<>
|
})}
|
||||||
<RiFileCopyLine size={24} style={{ marginRight: '8px' }} />
|
>
|
||||||
{t('shareDialog.copyButton')}
|
<Text as="p" wrap="pretty">
|
||||||
</>
|
{roomUrl?.replace(/^https?:\/\//, '')}
|
||||||
)}
|
</Text>
|
||||||
</Button>
|
{isTelephonyReadyForUse && roomUrl && (
|
||||||
|
<Button
|
||||||
|
variant={isRoomUrlCopied ? 'success' : 'tertiaryText'}
|
||||||
|
square
|
||||||
|
size={'sm'}
|
||||||
|
onPress={() => {
|
||||||
|
navigator.clipboard.writeText(roomUrl)
|
||||||
|
setIsRoomUrlCopied(true)
|
||||||
|
}}
|
||||||
|
aria-label={t('copyUrl')}
|
||||||
|
tooltip={t('copyUrl')}
|
||||||
|
>
|
||||||
|
{isRoomUrlCopied ? <RiCheckLine /> : <RiFileCopyLine />}
|
||||||
|
</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>
|
||||||
|
{clipboardContent && (
|
||||||
|
<Button
|
||||||
|
variant={isCopied ? 'success' : 'secondaryText'}
|
||||||
|
size="sm"
|
||||||
|
fullWidth
|
||||||
|
aria-label={t('copy')}
|
||||||
|
style={{
|
||||||
|
justifyContent: 'start',
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
navigator.clipboard.writeText(clipboardContent)
|
||||||
|
setIsCopied(true)
|
||||||
|
}}
|
||||||
|
data-attr="share-dialog-copy"
|
||||||
|
>
|
||||||
|
{isCopied ? (
|
||||||
|
<>
|
||||||
|
<RiCheckLine size={18} style={{ marginRight: '8px' }} />
|
||||||
|
{t('copied')}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<RiFileCopyLine
|
||||||
|
style={{ marginRight: '6px', minWidth: '18px' }}
|
||||||
|
/>
|
||||||
|
{t('copy')}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant={isCopied ? 'success' : 'tertiary'}
|
||||||
|
fullWidth
|
||||||
|
aria-label={t('copy')}
|
||||||
|
onPress={() => {
|
||||||
|
navigator.clipboard.writeText(roomUrl)
|
||||||
|
setIsCopied(true)
|
||||||
|
}}
|
||||||
|
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 && (
|
{roomData?.access_level === ApiAccessLevel.PUBLIC && (
|
||||||
<HStack>
|
<HStack>
|
||||||
<div
|
<div
|
||||||
@@ -117,7 +237,7 @@ export const InviteDialog = (props: Omit<DialogProps, 'title'>) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Text variant="sm" style={{ marginTop: '1rem' }}>
|
<Text variant="sm" style={{ marginTop: '1rem' }}>
|
||||||
{t('shareDialog.permissions')}
|
{t('permissions')}
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -53,12 +53,20 @@
|
|||||||
},
|
},
|
||||||
"leaveRoomPrompt": "Dadurch verlassen Sie das Meeting.",
|
"leaveRoomPrompt": "Dadurch verlassen Sie das Meeting.",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
"copy": "Meeting-Link kopieren",
|
"copy": "Informationen kopieren",
|
||||||
"copyButton": "Link kopieren",
|
"copyUrl": "Link kopieren",
|
||||||
"copied": "Link in die Zwischenablage kopiert",
|
"copied": "Informationen kopiert",
|
||||||
"heading": "Ihr Meeting ist bereit",
|
"heading": "Ihr Meeting ist bereit",
|
||||||
"description": "Teilen Sie diesen Link mit Personen, die Sie zum Meeting einladen möchten.",
|
"description": "Teilen Sie diesen Link mit Personen, die Sie zum Meeting einladen möchten.",
|
||||||
"permissions": "Personen mit diesem Link benötigen keine Erlaubnis, um diesem Meeting beizutreten."
|
"permissions": "Personen mit diesem Link benötigen keine Erlaubnis, um diesem Meeting beizutreten.",
|
||||||
|
"phone": {
|
||||||
|
"call": "Rufen Sie an:",
|
||||||
|
"pinCode": "Code:"
|
||||||
|
},
|
||||||
|
"clipboard": {
|
||||||
|
"url": "Um an der Videokonferenz teilzunehmen, klicken Sie auf diesen Link: {{roomUrl}}",
|
||||||
|
"numberAndPin": "Um telefonisch teilzunehmen, wählen Sie {{phoneNumber}} und geben Sie diesen Code ein: {{pinCode}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mediaErrorDialog": {
|
"mediaErrorDialog": {
|
||||||
"DeviceInUse": {
|
"DeviceInUse": {
|
||||||
|
|||||||
@@ -53,12 +53,20 @@
|
|||||||
},
|
},
|
||||||
"leaveRoomPrompt": "This will make you leave the meeting.",
|
"leaveRoomPrompt": "This will make you leave the meeting.",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
"copy": "Copy the meeting link",
|
"copy": "Copy information",
|
||||||
"copyButton": "Copy link",
|
"copyUrl": "Copy link",
|
||||||
"copied": "Link copied to clipboard",
|
"copied": "Information copied to clipboard",
|
||||||
"heading": "Your meeting is ready",
|
"heading": "Your meeting is ready",
|
||||||
"description": "Share this link with people you want to invite to the meeting.",
|
"description": "Share this link with people you want to invite to the meeting.",
|
||||||
"permissions": "People with this link do not need your permission to join this meeting."
|
"permissions": "People with this link do not need your permission to join this meeting.",
|
||||||
|
"phone": {
|
||||||
|
"call": "Call:",
|
||||||
|
"pinCode": "Code:"
|
||||||
|
},
|
||||||
|
"clipboard": {
|
||||||
|
"url": "To join the video conference, click on this link: {{roomUrl}}",
|
||||||
|
"numberAndPin": "To join by phone, dial {{phoneNumber}} and enter this code: {{pinCode}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mediaErrorDialog": {
|
"mediaErrorDialog": {
|
||||||
"DeviceInUse": {
|
"DeviceInUse": {
|
||||||
|
|||||||
@@ -53,12 +53,20 @@
|
|||||||
},
|
},
|
||||||
"leaveRoomPrompt": "Revenir à l'accueil vous fera quitter la réunion.",
|
"leaveRoomPrompt": "Revenir à l'accueil vous fera quitter la réunion.",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
"copy": "Copier le lien de la réunion",
|
"copy": "Copier les informations",
|
||||||
"copyButton": "Copier le lien",
|
"copyUrl": "Copier le lien",
|
||||||
"copied": "Lien copié dans le presse-papiers",
|
"copied": "Copiées dans le presse-papiers",
|
||||||
"heading": "Votre réunion est prête",
|
"heading": "Votre réunion est prête",
|
||||||
"description": "Partagez ce lien avec les personnes que vous souhaitez inviter à la réunion.",
|
"description": "Partagez ces informations 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."
|
"permissions": "Les personnes disposant de ce lien n'ont pas besoin de votre autorisation pour rejoindre cette réunion.",
|
||||||
|
"phone": {
|
||||||
|
"call": "Appelez le :",
|
||||||
|
"pinCode": "Code :"
|
||||||
|
},
|
||||||
|
"clipboard": {
|
||||||
|
"url": "Pour participer à la visioconférence, cliquez sur ce lien : {{roomUrl}}",
|
||||||
|
"numberAndPin": "Pour participer par téléphone, composez le {{phoneNumber}} et saisissez ce code : {{pinCode}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mediaErrorDialog": {
|
"mediaErrorDialog": {
|
||||||
"DeviceInUse": {
|
"DeviceInUse": {
|
||||||
|
|||||||
@@ -53,12 +53,20 @@
|
|||||||
},
|
},
|
||||||
"leaveRoomPrompt": "Dat zal u de vergadering doen verlaten.",
|
"leaveRoomPrompt": "Dat zal u de vergadering doen verlaten.",
|
||||||
"shareDialog": {
|
"shareDialog": {
|
||||||
"copy": "Kopieer de vergaderlink",
|
"copy": "Informatie kopiëren",
|
||||||
"copyButton": "Kopieerlink",
|
"copyUrl": "Kopieerlink",
|
||||||
"copied": "Link gekopieerd naar het klembord",
|
"copied": "Informatie gekopieerd",
|
||||||
"heading": "Uw vergadering is klaar",
|
"heading": "Uw vergadering is klaar",
|
||||||
"description": "Deel deze link met mensen die u wilt uitnodigen voor de vergadering.",
|
"description": "Deel deze link met mensen die u wilt uitnodigen voor de vergadering.",
|
||||||
"permissions": "Mensen met deze link hebben uw toestemming niet nodig om deel te nemen aan deze vergadering."
|
"permissions": "Mensen met deze link hebben uw toestemming niet nodig om deel te nemen aan deze vergadering.",
|
||||||
|
"phone": {
|
||||||
|
"call": "Bel:",
|
||||||
|
"pinCode": "Code:"
|
||||||
|
},
|
||||||
|
"clipboard": {
|
||||||
|
"url": "Klik op deze link om deel te nemen aan de videoconferentie: {{roomUrl}}",
|
||||||
|
"numberAndPin": "Bel {{phoneNumber}} en voer deze code in om telefonisch deel te nemen: {{pinCode}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mediaErrorDialog": {
|
"mediaErrorDialog": {
|
||||||
"DeviceInUse": {
|
"DeviceInUse": {
|
||||||
|
|||||||
Reference in New Issue
Block a user