diff --git a/src/frontend/src/features/recording/components/LimitReachedAlertDialog.tsx b/src/frontend/src/features/recording/components/LimitReachedAlertDialog.tsx index 65b57394..ad2481e5 100644 --- a/src/frontend/src/features/recording/components/LimitReachedAlertDialog.tsx +++ b/src/frontend/src/features/recording/components/LimitReachedAlertDialog.tsx @@ -2,22 +2,49 @@ import { useTranslation } from 'react-i18next' import { Button, Dialog, P } from '@/primitives' import { HStack } from '@/styled-system/jsx' import { useHumanizeRecordingMaxDuration } from '@/features/recording' +import { useEffect, useState } from 'react' +import { NotificationType } from '@/features/notifications' +import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner' +import { RoomEvent } from 'livekit-client' +import { decodeNotificationDataReceived } from '@/features/notifications/utils' +import { useRoomContext } from '@livekit/components-react' + +export const LimitReachedAlertDialog = () => { + const [isAlertOpen, setIsAlertOpen] = useState(false) -export const LimitReachedAlertDialog = ({ - isOpen, - onClose, -}: { - isOpen: boolean - onClose: () => void -}) => { const { t } = useTranslation('rooms', { keyPrefix: 'recordingStateToast.limitReachedAlert', }) + const room = useRoomContext() + const isAdminOrOwner = useIsAdminOrOwner() const maxDuration = useHumanizeRecordingMaxDuration() + useEffect(() => { + const handleDataReceived = (payload: Uint8Array) => { + if (!isAdminOrOwner) return + + const notification = decodeNotificationDataReceived(payload) + + if ( + notification?.type === NotificationType.TranscriptionLimitReached || + notification?.type === NotificationType.ScreenRecordingLimitReached + ) { + setIsAlertOpen(true) + } + } + + room.on(RoomEvent.DataReceived, handleDataReceived) + + return () => { + room.off(RoomEvent.DataReceived, handleDataReceived) + } + }, [room, isAdminOrOwner]) + + if (!isAdminOrOwner) return null + return ( - +

{t('description', { duration_message: maxDuration @@ -28,7 +55,7 @@ export const LimitReachedAlertDialog = ({ })}

- diff --git a/src/frontend/src/features/recording/components/RecordingProvider.tsx b/src/frontend/src/features/recording/components/RecordingProvider.tsx new file mode 100644 index 00000000..61f13098 --- /dev/null +++ b/src/frontend/src/features/recording/components/RecordingProvider.tsx @@ -0,0 +1,11 @@ +import { LimitReachedAlertDialog } from './LimitReachedAlertDialog' +import { RecordingStateToast } from './RecordingStateToast' + +export const RecordingProvider = () => { + return ( + <> + + + + ) +} diff --git a/src/frontend/src/features/recording/components/RecordingStateToast.tsx b/src/frontend/src/features/recording/components/RecordingStateToast.tsx index 5c084268..a29bd4f4 100644 --- a/src/frontend/src/features/recording/components/RecordingStateToast.tsx +++ b/src/frontend/src/features/recording/components/RecordingStateToast.tsx @@ -1,7 +1,7 @@ import { css } from '@/styled-system/css' import { useTranslation } from 'react-i18next' import { Spinner } from '@/primitives/Spinner' -import { useMemo, useState } from 'react' +import { useMemo } from 'react' import { Text } from '@/primitives' import { RiRecordCircleLine } from '@remixicon/react' import { @@ -12,8 +12,6 @@ import { import { FeatureFlags } from '@/features/analytics/enums' import { Button as RACButton } from 'react-aria-components' import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel' -import { useIsAdminOrOwner } from '@/features/rooms/livekit/hooks/useIsAdminOrOwner' -import { LimitReachedAlertDialog } from './LimitReachedAlertDialog' import { useRoomMetadata } from '../hooks/useRoomMetadata' export const RecordingStateToast = () => { @@ -21,10 +19,7 @@ export const RecordingStateToast = () => { keyPrefix: 'recordingStateToast', }) - const isAdminOrOwner = useIsAdminOrOwner() - const { openTranscript, openScreenRecording } = useSidePanel() - const [isAlertOpen, setIsAlertOpen] = useState(false) const hasTranscriptAccess = useHasRecordingAccess( RecordingMode.Transcript, @@ -65,14 +60,7 @@ export const RecordingStateToast = () => { return `${metadata.recording_mode}.${metadata.recording_status}` }, [metadata, isStarted, isStarting]) - if (!key) - return isAdminOrOwner ? ( - setIsAlertOpen(false)} - aria-label="Recording limit exceeded" - /> - ) : null + if (!key) return null const hasScreenRecordingAccessAndActive = isScreenRecordingActive && hasScreenRecordingAccess diff --git a/src/frontend/src/features/recording/index.ts b/src/frontend/src/features/recording/index.ts index a0b0bcee..a1e590c2 100644 --- a/src/frontend/src/features/recording/index.ts +++ b/src/frontend/src/features/recording/index.ts @@ -11,7 +11,7 @@ export { useStopRecording } from './api/stopRecording' export { RecordingMode, RecordingStatus } from './types' // components -export { RecordingStateToast } from './components/RecordingStateToast' +export { RecordingProvider } from './components/RecordingProvider' export { TranscriptSidePanel } from './components/TranscriptSidePanel' export { ScreenRecordingSidePanel } from './components/ScreenRecordingSidePanel' diff --git a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx index edffa7e3..cee1eece 100644 --- a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx +++ b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx @@ -26,7 +26,7 @@ import { FocusLayout } from '../components/FocusLayout' import { ParticipantTile } from '../components/ParticipantTile' import { SidePanel } from '../components/SidePanel' import { useSidePanel } from '../hooks/useSidePanel' -import { RecordingStateToast } from '@/features/recording' +import { RecordingProvider } from '@/features/recording' import { ScreenShareErrorModal } from '../components/ScreenShareErrorModal' import { useConnectionObserver } from '../hooks/useConnectionObserver' import { useNoiseReduction } from '../hooks/useNoiseReduction' @@ -261,7 +261,7 @@ export function VideoConference({ ...props }: VideoConferenceProps) { )} - + )