🚸(frontend) add permission hints and modal button to join screen
Add explicit messaging on join screen explaining why users should allow camera/microphone access, with quick button to open permission modal dialog. Targets first-time users who need guidance on permission requirements. Message persists until permissions are granted to ensure proper user onboarding and reduce support issues.
This commit is contained in:
committed by
aleb_the_flash
parent
4fae3c6c47
commit
0e72f61650
@@ -27,6 +27,8 @@ import { ApiLobbyStatus, ApiRequestEntry } from '../api/requestEntry'
|
|||||||
import { Spinner } from '@/primitives/Spinner'
|
import { Spinner } from '@/primitives/Spinner'
|
||||||
import { ApiAccessLevel } from '../api/ApiRoom'
|
import { ApiAccessLevel } from '../api/ApiRoom'
|
||||||
import { useLoginHint } from '@/hooks/useLoginHint'
|
import { useLoginHint } from '@/hooks/useLoginHint'
|
||||||
|
import { useSnapshot } from 'valtio'
|
||||||
|
import { openPermissionsDialog, permissionsStore } from '@/stores/permissions'
|
||||||
|
|
||||||
const onError = (e: Error) => console.error('ERROR', e)
|
const onError = (e: Error) => console.error('ERROR', e)
|
||||||
|
|
||||||
@@ -220,19 +222,48 @@ export const Join = ({
|
|||||||
enterRoom()
|
enterRoom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const permissions = useSnapshot(permissionsStore)
|
||||||
|
|
||||||
|
const isCameraDeniedOrPrompted =
|
||||||
|
permissions.isCameraDenied || permissions.isCameraPrompted
|
||||||
|
|
||||||
|
const isMicrophoneDeniedOrPrompted =
|
||||||
|
permissions.isMicrophoneDenied || permissions.isMicrophonePrompted
|
||||||
|
|
||||||
const hintMessage = useMemo(() => {
|
const hintMessage = useMemo(() => {
|
||||||
|
if (isCameraDeniedOrPrompted) {
|
||||||
|
return isMicrophoneDeniedOrPrompted
|
||||||
|
? 'cameraAndMicNotGranted'
|
||||||
|
: 'cameraNotGranted'
|
||||||
|
}
|
||||||
if (!videoEnabled) {
|
if (!videoEnabled) {
|
||||||
return 'cameraDisabled'
|
return 'cameraDisabled'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isVideoInitiated.current) {
|
if (!isVideoInitiated.current) {
|
||||||
return 'cameraStarting'
|
return 'cameraStarting'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoTrack && videoEnabled) {
|
if (videoTrack && videoEnabled) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}, [videoTrack, videoEnabled])
|
}, [
|
||||||
|
videoTrack,
|
||||||
|
videoEnabled,
|
||||||
|
isCameraDeniedOrPrompted,
|
||||||
|
isMicrophoneDeniedOrPrompted,
|
||||||
|
])
|
||||||
|
|
||||||
|
const permissionsButtonLabel = useMemo(() => {
|
||||||
|
if (!isMicrophoneDeniedOrPrompted && !isCameraDeniedOrPrompted) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (isCameraDeniedOrPrompted && isMicrophoneDeniedOrPrompted) {
|
||||||
|
return 'cameraAndMicNotGranted'
|
||||||
|
}
|
||||||
|
if (isCameraDeniedOrPrompted && !isMicrophoneDeniedOrPrompted) {
|
||||||
|
return 'cameraNotGranted'
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}, [isMicrophoneDeniedOrPrompted, isCameraDeniedOrPrompted])
|
||||||
|
|
||||||
const renderWaitingState = () => {
|
const renderWaitingState = () => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -416,7 +447,10 @@ export const Join = ({
|
|||||||
width="1280"
|
width="1280"
|
||||||
height="720"
|
height="720"
|
||||||
style={{
|
style={{
|
||||||
display: !videoEnabled ? 'none' : undefined,
|
display:
|
||||||
|
!videoEnabled || isCameraDeniedOrPrompted
|
||||||
|
? 'none'
|
||||||
|
: undefined,
|
||||||
}}
|
}}
|
||||||
className={css({
|
className={css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -443,6 +477,7 @@ export const Join = ({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '0.24rem',
|
padding: '0.24rem',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
|
gap: '1rem',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
@@ -455,6 +490,15 @@ export const Join = ({
|
|||||||
>
|
>
|
||||||
{hintMessage && t(hintMessage)}
|
{hintMessage && t(hintMessage)}
|
||||||
</p>
|
</p>
|
||||||
|
{isCameraDeniedOrPrompted && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="tertiary"
|
||||||
|
onPress={openPermissionsDialog}
|
||||||
|
>
|
||||||
|
{t(`permissionsButton.${permissionsButtonLabel}`)}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -37,7 +37,13 @@
|
|||||||
"usernameEmpty": "Ihr Name darf nicht leer sein"
|
"usernameEmpty": "Ihr Name darf nicht leer sein"
|
||||||
},
|
},
|
||||||
"cameraDisabled": "Kamera ist deaktiviert.",
|
"cameraDisabled": "Kamera ist deaktiviert.",
|
||||||
"cameraStarting": "Kamera wird gestartet.",
|
"cameraStarting": "Kamera wird gestartet…",
|
||||||
|
"cameraNotGranted": "Möchten Sie, dass andere Sie während der Besprechung sehen können?",
|
||||||
|
"cameraAndMicNotGranted": "Möchten Sie, dass andere Sie während der Besprechung sehen und hören können?",
|
||||||
|
"permissionsButton": {
|
||||||
|
"cameraAndMicNotGranted": "Zugriff auf Kamera und Mikrofon erlauben",
|
||||||
|
"cameraNotGranted": "Zugriff auf Kamera erlauben"
|
||||||
|
},
|
||||||
"waiting": {
|
"waiting": {
|
||||||
"title": "Beitrittsanfrage wird gesendet...",
|
"title": "Beitrittsanfrage wird gesendet...",
|
||||||
"body": "Sie können diesem Anruf beitreten, sobald jemand Sie autorisiert"
|
"body": "Sie können diesem Anruf beitreten, sobald jemand Sie autorisiert"
|
||||||
|
|||||||
@@ -37,7 +37,13 @@
|
|||||||
"usernameEmpty": "Your name cannot be empty"
|
"usernameEmpty": "Your name cannot be empty"
|
||||||
},
|
},
|
||||||
"cameraDisabled": "Camera is disabled.",
|
"cameraDisabled": "Camera is disabled.",
|
||||||
"cameraStarting": "Camera is starting.",
|
"cameraStarting": "Camera is starting…",
|
||||||
|
"cameraNotGranted": "Would you like others to be able to see you during the meeting?",
|
||||||
|
"cameraAndMicNotGranted": "Would you like others to be able to see and hear you during the meeting?",
|
||||||
|
"permissionsButton": {
|
||||||
|
"cameraAndMicNotGranted": "Allow access to camera and microphone",
|
||||||
|
"cameraNotGranted": "Allow access to camera"
|
||||||
|
},
|
||||||
"waiting": {
|
"waiting": {
|
||||||
"title": "Requesting to join...",
|
"title": "Requesting to join...",
|
||||||
"body": "You will be able to join this call when someone authorizes you"
|
"body": "You will be able to join this call when someone authorizes you"
|
||||||
|
|||||||
@@ -37,7 +37,13 @@
|
|||||||
"usernameEmpty": "Votre nom ne peut pas être vide"
|
"usernameEmpty": "Votre nom ne peut pas être vide"
|
||||||
},
|
},
|
||||||
"cameraDisabled": "La caméra est désactivée.",
|
"cameraDisabled": "La caméra est désactivée.",
|
||||||
"cameraStarting": "La caméra va démarrer.",
|
"cameraStarting": "La caméra va démarrer…",
|
||||||
|
"cameraNotGranted": "Souhaitez-vous que les autres puissent vous voir pendant la réunion ?",
|
||||||
|
"cameraAndMicNotGranted": "Souhaitez-vous que les autres puissent vous voir et vous entendre pendant la réunion ?",
|
||||||
|
"permissionsButton": {
|
||||||
|
"cameraAndMicNotGranted": "Autorisez l'accès à la caméra et au micro",
|
||||||
|
"cameraNotGranted": "Autorisez l'accès à la caméra"
|
||||||
|
},
|
||||||
"waiting": {
|
"waiting": {
|
||||||
"title": "Demande de participation…",
|
"title": "Demande de participation…",
|
||||||
"body": "Vous pourrez participer à cet appel lorsque quelqu'un vous y autorisera"
|
"body": "Vous pourrez participer à cet appel lorsque quelqu'un vous y autorisera"
|
||||||
|
|||||||
@@ -37,7 +37,13 @@
|
|||||||
"usernameEmpty": "Uw naam kan niet leeg zijn"
|
"usernameEmpty": "Uw naam kan niet leeg zijn"
|
||||||
},
|
},
|
||||||
"cameraDisabled": "Camera is uitgeschakeld.",
|
"cameraDisabled": "Camera is uitgeschakeld.",
|
||||||
"cameraStarting": "Camera wordt ingeschakeld.",
|
"cameraStarting": "Camera wordt ingeschakeld…",
|
||||||
|
"cameraNotGranted": "Wilt u dat anderen u tijdens de vergadering kunnen zien?",
|
||||||
|
"cameraAndMicNotGranted": "Wilt u dat anderen u tijdens de vergadering kunnen zien en horen?",
|
||||||
|
"permissionsButton": {
|
||||||
|
"cameraAndMicNotGranted": "Toegang tot camera en microfoon toestaan",
|
||||||
|
"cameraNotGranted": "Toegang tot camera toestaan"
|
||||||
|
},
|
||||||
"waiting": {
|
"waiting": {
|
||||||
"title": "Verzoek tot deelname...",
|
"title": "Verzoek tot deelname...",
|
||||||
"body": "U kunt deelnemen aan dit gesprek wanneer iemand u toestemming geeft"
|
"body": "U kunt deelnemen aan dit gesprek wanneer iemand u toestemming geeft"
|
||||||
|
|||||||
Reference in New Issue
Block a user