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