🚸(frontend) add login hint for unauthenticated users in lobby

Add informational message suggesting authentication for users waiting in
lobby without being logged in. Highlight that logging in could grant
immediate access without admin approval when rooms have trusted
access level enabled.
This commit is contained in:
lebaudantoine
2025-03-04 18:39:45 +01:00
committed by aleb_the_flash
parent 00cd4fc92a
commit aaf1163910
7 changed files with 128 additions and 3 deletions

View File

@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'
import { usePreviewTracks } from '@livekit/components-react'
import { css } from '@/styled-system/css'
import { Screen } from '@/layout/Screen'
import { useMemo, useEffect, useRef, useState, useCallback } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { LocalVideoTrack, Track } from 'livekit-client'
import { H } from '@/primitives/H'
import { SelectToggleDevice } from '../livekit/components/controls/SelectToggleDevice'
@@ -26,6 +26,8 @@ import { useQuery } from '@tanstack/react-query'
import { queryClient } from '@/api/queryClient'
import { ApiLobbyStatus, ApiRequestEntry } from '../api/requestEntry'
import { Spinner } from '@/primitives/Spinner'
import { ApiAccessLevel } from '../api/ApiRoom'
import { useLoginHint } from '@/hooks/useLoginHint'
const onError = (e: Error) => console.error('ERROR', e)
@@ -264,10 +266,16 @@ export const Join = ({
onAccepted: handleAccepted,
})
const { openLoginHint } = useLoginHint()
const handleSubmit = async () => {
const { data } = await refetchRoom()
if (!data?.livekit) {
// Display a message to inform the user that by logging in, they won't have to wait for room entry approval.
if (data?.access_level == ApiAccessLevel.TRUSTED) {
openLoginHint()
}
startWaiting()
return
}

View File

@@ -0,0 +1,22 @@
import { useSnapshot } from 'valtio'
import { hintsStore } from '@/stores/hints'
import { useUser } from '@/features/auth'
import { useEffect } from 'react'
export const useLoginHint = () => {
const hintsSnap = useSnapshot(hintsStore)
const { isLoggedIn } = useUser()
const openLoginHint = () => (hintsStore.showLoginHint = true)
const closeLoginHint = () => (hintsStore.showLoginHint = false)
useEffect(() => {
if (isLoggedIn && hintsSnap.showLoginHint) closeLoginHint()
}, [isLoggedIn, hintsSnap])
return {
isVisible: hintsSnap.showLoginHint,
openLoginHint,
closeLoginHint,
}
}

View File

@@ -2,7 +2,7 @@ import { Link } from 'wouter'
import { css } from '@/styled-system/css'
import { HStack, Stack } from '@/styled-system/jsx'
import { useTranslation } from 'react-i18next'
import { Button } from '@/primitives'
import { Button, Text } from '@/primitives'
import { SettingsButton } from '@/features/settings'
import { useUser } from '@/features/auth'
import { useMatchesRoute } from '@/navigation/useMatchesRoute'
@@ -12,6 +12,7 @@ import { MenuList } from '@/primitives/MenuList'
import { ProConnectButton } from '@/components/ProConnectButton'
import LogoAsset from '@/assets/logo.svg'
import { useLoginHint } from '@/hooks/useLoginHint'
const Marianne = () => {
return (
@@ -91,6 +92,64 @@ const Logo = () => {
)
}
const LoginHint = () => {
const { t } = useTranslation()
const { isVisible, closeLoginHint } = useLoginHint()
if (!isVisible) return null
return (
<div
className={css({
position: 'absolute',
top: '103px',
right: '110px',
zIndex: '100',
outline: 'none',
padding: '1.25rem',
maxWidth: '350px',
boxShadow: '0 2px 5px rgba(0 0 0 / 0.1)',
borderRadius: '1rem',
backgroundColor: 'primary.200',
display: 'none',
xsm: {
display: 'block',
},
sm: {
top: '131px',
right: '100px',
zIndex: '100',
},
_after: {
content: '""',
position: 'absolute',
top: '-10px',
right: '20%',
marginLeft: '-10px',
borderWidth: '0 10px 10px 10px',
borderStyle: 'solid',
borderColor: 'transparent transparent #E3E3FB transparent',
},
})}
>
<Text variant="h3" margin={false} bold>
{t('loginHint.title')}
</Text>
<Text variant="paragraph" margin={false}>
{t('loginHint.body')}
</Text>
<Button
aria-label={t('loginHint.button.ariaLabel')}
size="sm"
className={css({
marginLeft: 'auto',
})}
onPress={() => closeLoginHint()}
>
{t('loginHint.button.label')}
</Button>
</div>
)
}
export const Header = () => {
const { t } = useTranslation()
const isHome = useMatchesRoute('home')
@@ -144,7 +203,10 @@ export const Header = () => {
<nav>
<Stack gap={1} direction="row" align="center">
{isLoggedIn === false && !isHome && (
<ProConnectButton hint={false} />
<>
<ProConnectButton hint={false} />
<LoginHint />
</>
)}
{!!user && (
<Menu>

View File

@@ -41,5 +41,13 @@
},
"mentions": "",
"license": ""
},
"loginHint": {
"title": "",
"body": "",
"button": {
"ariaLabel": "",
"label": ""
}
}
}

View File

@@ -41,5 +41,13 @@
},
"mentions": "Unless otherwise stated, the contents of this site are available under",
"license": "etalab 2.0 license"
},
"loginHint": {
"title": "Log in with your ProConnect account",
"body": "Instead of waiting, log in with your ProConnect account.",
"button": {
"ariaLabel": "Close the suggestion",
"label": "OK"
}
}
}

View File

@@ -41,5 +41,13 @@
},
"mentions": "Sauf mention contraire, les contenus de ce site sont disponibles sous",
"license": "licence etalab 2.0"
},
"loginHint": {
"title": "Connectez-vous avec votre compte ProConnect",
"body": "Au lieu de patienter, connectez-vous avec votre compte ProConnect.",
"button": {
"ariaLabel": "Fermer la suggestion",
"label": "OK"
}
}
}

View File

@@ -0,0 +1,9 @@
import { proxy } from 'valtio'
type State = {
showLoginHint: boolean
}
export const hintsStore = proxy<State>({
showLoginHint: false,
})