From e5af74685e8be094da43fec300554bb16f4a8aeb Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Thu, 17 Apr 2025 11:58:32 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(frontend)=20introduce=20dedicated=20r?= =?UTF-8?q?ecording=20download=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create initial version of dedicated page for recording downloads, linked directly from email notifications sent to users. Implementation is basic but functional, serving as temporary solution until files can be stored in drive storage. Enables recipients to access recordings through direct links. --- src/frontend/src/features/recording/index.ts | 3 + .../recording/routes/RecordingDownload.tsx | 81 +++++++++++++++++++ src/frontend/src/locales/de/recording.json | 15 ++++ src/frontend/src/locales/en/recording.json | 15 ++++ src/frontend/src/locales/fr/recording.json | 15 ++++ src/frontend/src/locales/nl/recording.json | 15 ++++ src/frontend/src/routes.ts | 12 ++- 7 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/frontend/src/features/recording/routes/RecordingDownload.tsx create mode 100644 src/frontend/src/locales/de/recording.json create mode 100644 src/frontend/src/locales/en/recording.json create mode 100644 src/frontend/src/locales/fr/recording.json create mode 100644 src/frontend/src/locales/nl/recording.json diff --git a/src/frontend/src/features/recording/index.ts b/src/frontend/src/features/recording/index.ts index b2c29a0e..386819cd 100644 --- a/src/frontend/src/features/recording/index.ts +++ b/src/frontend/src/features/recording/index.ts @@ -13,3 +13,6 @@ export { RecordingMode } from './types' export { RecordingStateToast } from './components/RecordingStateToast' export { TranscriptSidePanel } from './components/TranscriptSidePanel' export { ScreenRecordingSidePanel } from './components/ScreenRecordingSidePanel' + +// routes +export { RecordingDownload as RecordingDownloadRoute } from './routes/RecordingDownload' diff --git a/src/frontend/src/features/recording/routes/RecordingDownload.tsx b/src/frontend/src/features/recording/routes/RecordingDownload.tsx new file mode 100644 index 00000000..f79d2eec --- /dev/null +++ b/src/frontend/src/features/recording/routes/RecordingDownload.tsx @@ -0,0 +1,81 @@ +import { useParams } from 'wouter' +import { useQuery } from '@tanstack/react-query' +import { Center, VStack } from '@/styled-system/jsx' +import { css } from '@/styled-system/css' +import { useTranslation } from 'react-i18next' +import fourthSlide from '@/assets/intro-slider/4_record.png' +import { mediaUrl } from '@/api/mediaUrl' +import { UserAware, useUser } from '@/features/auth' +import { Screen } from '@/layout/Screen' +import { H, LinkButton, Text } from '@/primitives' +import { formatDate } from '@/utils/formatDate' +import { ErrorScreen } from '@/components/ErrorScreen' +import { LoadingScreen } from '@/components/LoadingScreen' +import { fetchRecording } from '../api/fetchRecording' + +export const RecordingDownload = () => { + const { t } = useTranslation('recording') + const { recordingId } = useParams() + const { isLoggedIn } = useUser() + + const { data, isLoading, isError } = useQuery({ + queryKey: ['recording', recordingId], + queryFn: () => fetchRecording({ recordingId }), + retry: false, + enabled: !!recordingId, + }) + + if (isLoading || !data) { + return + } + + if (!isLoggedIn) { + return ( + + ) + } + + if (isError) { + return + } + + return ( + + +
+ + {''} + + {t('success.title')} + + + + + + {t('success.button')} + + +
+
+
+ ) +} diff --git a/src/frontend/src/locales/de/recording.json b/src/frontend/src/locales/de/recording.json new file mode 100644 index 00000000..ef8502a1 --- /dev/null +++ b/src/frontend/src/locales/de/recording.json @@ -0,0 +1,15 @@ +{ + "error": { + "title": "", + "body": "" + }, + "authentication": { + "title": "", + "body": "" + }, + "success": { + "title": "", + "body": "", + "button": "" + } +} diff --git a/src/frontend/src/locales/en/recording.json b/src/frontend/src/locales/en/recording.json new file mode 100644 index 00000000..fff09fb0 --- /dev/null +++ b/src/frontend/src/locales/en/recording.json @@ -0,0 +1,15 @@ +{ + "error": { + "title": "Recording unavailable", + "body": "This recording could not be found or was deleted after its 7-day validity period." + }, + "authentication": { + "title": "Authentication required", + "body": "Please log in to access this recording." + }, + "success": { + "title": "Your recording is ready!", + "body": "Recording of the meeting {{room}} from {{created_at}}.", + "button": "Download" + } +} diff --git a/src/frontend/src/locales/fr/recording.json b/src/frontend/src/locales/fr/recording.json new file mode 100644 index 00000000..5818e570 --- /dev/null +++ b/src/frontend/src/locales/fr/recording.json @@ -0,0 +1,15 @@ +{ + "error": { + "title": "Enregistrement indisponible", + "body": "Cet enregistrement est introuvable ou a été supprimé après sa période de validité de 7 jours." + }, + "authentication": { + "title": "Authentification requise", + "body": "Veuillez vous connecter pour accéder à cet enregistrement." + }, + "success": { + "title": "Votre enregistrement est prêt !", + "body": "Enregistrement de la réunion {{room}} du {{created_at}}.", + "button": "Télécharger" + } +} diff --git a/src/frontend/src/locales/nl/recording.json b/src/frontend/src/locales/nl/recording.json new file mode 100644 index 00000000..de3a9965 --- /dev/null +++ b/src/frontend/src/locales/nl/recording.json @@ -0,0 +1,15 @@ +{ + "error": { + "title": "Opname niet beschikbaar", + "body": "Deze opname is niet gevonden of is verwijderd na de geldigheidsperiode van 7 dagen." + }, + "authentication": { + "title": "Authenticatie vereist", + "body": "Log in om toegang te krijgen tot deze opname." + }, + "success": { + "title": "Je opname is klaar!", + "body": "Opname van de vergadering {{room}} op {{created_at}}.", + "button": "Downloaden" + } +} diff --git a/src/frontend/src/routes.ts b/src/frontend/src/routes.ts index 0783a15d..24e3f866 100644 --- a/src/frontend/src/routes.ts +++ b/src/frontend/src/routes.ts @@ -5,6 +5,7 @@ import { AccessibilityRoute } from '@/features/legalsTerms/Accessibility' import { TermsOfServiceRoute } from '@/features/legalsTerms/TermsOfService' import { CreatePopup } from '@/features/sdk/routes/CreatePopup' import { CreateMeetingButton } from '@/features/sdk/routes/CreateMeetingButton' +import { RecordingDownloadRoute } from '@/features/recording' export const routes: Record< | 'home' @@ -14,7 +15,8 @@ export const routes: Record< | 'accessibility' | 'termsOfService' | 'sdkCreatePopup' - | 'sdkCreateButton', + | 'sdkCreateButton' + | 'recordingDownload', { name: RouteName path: RegExp | string @@ -64,6 +66,14 @@ export const routes: Record< path: '/sdk/create-button', Component: CreateMeetingButton, }, + recordingDownload: { + name: 'recordingDownload', + path: new RegExp( + `^[/]recording[/](?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$` + ), + to: (recordingId: string) => `/recording/${recordingId.trim()}`, + Component: RecordingDownloadRoute, + }, } export type RouteName = keyof typeof routes