diff --git a/src/frontend/src/features/notifications/components/WaitingParticipantNotification.tsx b/src/frontend/src/features/notifications/components/WaitingParticipantNotification.tsx index fc9fd3f0..e916645d 100644 --- a/src/frontend/src/features/notifications/components/WaitingParticipantNotification.tsx +++ b/src/frontend/src/features/notifications/components/WaitingParticipantNotification.tsx @@ -1,100 +1,211 @@ -import { useListWaitingParticipants } from '@/features/rooms/api/listWaitingParticipants' -import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData' import { StyledToastContainer } from './Toast' -import { HStack } from '@/styled-system/jsx' +import { HStack, VStack } from '@/styled-system/jsx' import { Avatar } from '@/components/Avatar' -import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel' import { Button, Text } from '@/primitives' import { css } from '@/styled-system/css' import { RiInfinityLine } from '@remixicon/react' import { useTranslation } from 'react-i18next' +import { useEffect, useRef, useState } from 'react' +import { usePrevious } from '@/hooks/usePrevious' +import { WaitingParticipant } from '@/features/rooms/api/listWaitingParticipants' +import { useWaitingParticipants } from '@/features/rooms/hooks/useWaitingParticipants' +import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel' + +export const NOTIFICATION_DISPLAY_DURATION = 10000 export const WaitingParticipantNotification = () => { - const data = useRoomData() const { t } = useTranslation('notifications', { keyPrefix: 'waitingParticipants', }) + + const timerRef = useRef(null) const { isParticipantsOpen, toggleParticipants } = useSidePanel() - const { data: readOnlyData } = useListWaitingParticipants(data!.id, { - retry: false, - enabled: false, - }) - const participants = readOnlyData?.participants || [] - if (!participants.length) return + const [showQuickActionsMessage, setShowQuickActionsMessage] = useState(false) + const { waitingParticipants, handleParticipantEntry } = + useWaitingParticipants() + const prevWaitingParticipant = usePrevious( + waitingParticipants + ) + + const isParticipantListEmpty = (p?: WaitingParticipant[]) => p?.length == 0 + + useEffect(() => { + // Show notification when the first participant enters the waiting room + if ( + !isParticipantListEmpty(waitingParticipants) && + isParticipantListEmpty(prevWaitingParticipant) && + !isParticipantsOpen + ) { + setShowQuickActionsMessage(true) + if (timerRef.current !== null) { + clearTimeout(timerRef.current) + } + timerRef.current = setTimeout(() => { + setShowQuickActionsMessage(false) + timerRef.current = null // Clear the ref when timeout completes + }, NOTIFICATION_DISPLAY_DURATION) + } else if (waitingParticipants.length !== prevWaitingParticipant?.length) { + // Hide notification when the participant count changes + setShowQuickActionsMessage(false) + } + }, [waitingParticipants, prevWaitingParticipant, isParticipantsOpen]) + + useEffect(() => { + // This cleanup function will only run when the component unmounts + return () => { + if (timerRef.current !== null) { + clearTimeout(timerRef.current) + } + } + }, []) + + useEffect(() => { + // Hide notification when participants panel is opened + if (isParticipantsOpen) { + setShowQuickActionsMessage(false) + } + }, [isParticipantsOpen]) + + if (!waitingParticipants.length) return null + return ( 1 ? t('several') : t('one')} + aria-label={waitingParticipants.length > 1 ? t('several') : t('one')} aria-modal={false} > - - - {participants.length > 1 && ( - + - )} - {participants.length > 2 && ( - - {participants.length < 102 ? ( -

+{participants.length - 2}

- ) : ( - + {t('one')} +
+ + + + {waitingParticipants[0].username} + + + + + + + + ) : ( + <> + + + {waitingParticipants.length > 1 && ( + )} - - )} - - - {participants.length > 1 ? t('several') : t('one')} - - {!isParticipantsOpen && ( - + {waitingParticipants.length > 2 && ( + + {waitingParticipants.length < 102 ? ( +

+{waitingParticipants.length - 2}

+ ) : ( + + )} +
+ )} +
+ + {waitingParticipants.length > 1 ? t('several') : t('one')} + + {!isParticipantsOpen && ( + + )} + )}
diff --git a/src/frontend/src/locales/de/notifications.json b/src/frontend/src/locales/de/notifications.json index aa8c1508..0ef15bf3 100644 --- a/src/frontend/src/locales/de/notifications.json +++ b/src/frontend/src/locales/de/notifications.json @@ -19,6 +19,7 @@ "waitingParticipants": { "one": "", "several": "", - "open": "" + "open": "", + "accept": "" } } diff --git a/src/frontend/src/locales/en/notifications.json b/src/frontend/src/locales/en/notifications.json index 44f45cdf..45e55c27 100644 --- a/src/frontend/src/locales/en/notifications.json +++ b/src/frontend/src/locales/en/notifications.json @@ -19,6 +19,7 @@ "waitingParticipants": { "one": "One person wants to join this call.", "several": "Several people want to join this call.", - "open": "Open" + "open": "Open", + "accept": "Accept" } } diff --git a/src/frontend/src/locales/fr/notifications.json b/src/frontend/src/locales/fr/notifications.json index af88f072..9a0cef3d 100644 --- a/src/frontend/src/locales/fr/notifications.json +++ b/src/frontend/src/locales/fr/notifications.json @@ -19,6 +19,7 @@ "waitingParticipants": { "one": "Une personne souhaite participer à cet appel.", "several": "Plusieurs personnes souhaitent participer à cet appel.", - "open": "Afficher" + "open": "Afficher", + "accept": "Accepter" } }