From 236245740f3a0a707d4d67446cd6841046dcc14b Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Wed, 31 Dec 2025 16:47:45 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20refactor=20recor?= =?UTF-8?q?ding=20side=20panels=20to=20reduce=20code=20duplication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A lot of duplication existed, so I started factorizing components now that a proper user experience is clearer. Without over-abstracting, the first step introduces a reusable “no access” view with configurable message and image. This is just the beginning: props passing is still not ideal, but it’s sufficient to merge and significantly reduce duplication. --- .../recording/components/LoginPrompt.tsx | 45 +++++ .../recording/components/NoAccessView.tsx | 82 ++++++++ .../components/ScreenRecordingSidePanel.tsx | 99 +--------- .../components/TranscriptSidePanel.tsx | 185 ++---------------- src/frontend/src/locales/de/rooms.json | 1 + src/frontend/src/locales/en/rooms.json | 1 + src/frontend/src/locales/fr/rooms.json | 1 + src/frontend/src/locales/nl/rooms.json | 1 + 8 files changed, 152 insertions(+), 263 deletions(-) create mode 100644 src/frontend/src/features/recording/components/LoginPrompt.tsx create mode 100644 src/frontend/src/features/recording/components/NoAccessView.tsx diff --git a/src/frontend/src/features/recording/components/LoginPrompt.tsx b/src/frontend/src/features/recording/components/LoginPrompt.tsx new file mode 100644 index 00000000..9ee7825d --- /dev/null +++ b/src/frontend/src/features/recording/components/LoginPrompt.tsx @@ -0,0 +1,45 @@ +import { H, Text } from '@/primitives' +import { css } from '@/styled-system/css' +import { LoginButton } from '@/components/LoginButton' + +interface LoginPromptProps { + heading: string + body: string +} + +export const LoginPrompt = ({ heading, body }: LoginPromptProps) => { + return ( +
+ + {heading} + + + {body} + +
+ +
+
+ ) +} diff --git a/src/frontend/src/features/recording/components/NoAccessView.tsx b/src/frontend/src/features/recording/components/NoAccessView.tsx new file mode 100644 index 00000000..39872070 --- /dev/null +++ b/src/frontend/src/features/recording/components/NoAccessView.tsx @@ -0,0 +1,82 @@ +import { A, Div, Text } from '@/primitives' +import { css } from '@/styled-system/css' +import { useTranslation } from 'react-i18next' +import { LoginPrompt } from './LoginPrompt' +import { useUser } from '@/features/auth' + +interface NoAccessViewProps { + i18nKeyPrefix: string + i18nKey: string + helpArticle?: string + imagePath: string +} + +export const NoAccessView = ({ + i18nKeyPrefix, + i18nKey, + helpArticle, + imagePath, +}: NoAccessViewProps) => { + const { isLoggedIn } = useUser() + const { t } = useTranslation('rooms', { keyPrefix: i18nKeyPrefix }) + + return ( +
+ + {t(`${i18nKey}.heading`)} + + {t(`${i18nKey}.body`)} +
+ {helpArticle && ( + + {t(`${i18nKey}.linkMore`)} + + )} +
+ {!isLoggedIn && ( + + )} +
+ ) +} diff --git a/src/frontend/src/features/recording/components/ScreenRecordingSidePanel.tsx b/src/frontend/src/features/recording/components/ScreenRecordingSidePanel.tsx index 7b577093..b91b1d52 100644 --- a/src/frontend/src/features/recording/components/ScreenRecordingSidePanel.tsx +++ b/src/frontend/src/features/recording/components/ScreenRecordingSidePanel.tsx @@ -27,8 +27,7 @@ import { useConfig } from '@/api/useConfig' import humanizeDuration from 'humanize-duration' import i18n from 'i18next' import { FeatureFlags } from '@/features/analytics/enums' -import { LoginButton } from '@/components/LoginButton' -import { useUser } from '@/features/auth' +import { NoAccessView } from './NoAccessView' export const ScreenRecordingSidePanel = () => { const { data } = useConfig() @@ -43,8 +42,6 @@ export const ScreenRecordingSidePanel = () => { FeatureFlags.ScreenRecording ) - const { isLoggedIn } = useUser() - const { notifyParticipants } = useNotifyParticipants() const roomId = useRoomId() @@ -114,7 +111,7 @@ export const ScreenRecordingSidePanel = () => { posthog.capture('screen-recording-started', {}) } } catch (error) { - console.error('Failed to handle transcript:', error) + console.error('Failed to handle recording:', error) setIsLoading(false) } } @@ -130,92 +127,12 @@ export const ScreenRecordingSidePanel = () => { if (hasFeatureWithoutAdminRights) { return ( -
- {''} - {t('notAdminOrOwner.heading')} - - {t('notAdminOrOwner.body')} -
- {data?.support?.help_article_recording && ( - - {t('notAdminOrOwner.linkMore')} - - )} -
- {!isLoggedIn && ( -
- - {t('notAdminOrOwner.login.heading')} - - - {t('notAdminOrOwner.login.body')} - -
- -
-
- )} -
+ ) } diff --git a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx index dbd19d6d..55ff241b 100644 --- a/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx +++ b/src/frontend/src/features/recording/components/TranscriptSidePanel.tsx @@ -30,8 +30,6 @@ import { Spinner } from '@/primitives/Spinner' import { useConfig } from '@/api/useConfig' import humanizeDuration from 'humanize-duration' import i18n from 'i18next' -import { useUser } from '@/features/auth' -import { LoginButton } from '@/components/LoginButton' import { HStack, VStack } from '@/styled-system/jsx' import { Checkbox } from '@/primitives/Checkbox.tsx' @@ -40,12 +38,11 @@ import { SettingsDialogExtendedKey, useTranscriptionLanguageOptions, } from '@/features/settings' +import { NoAccessView } from './NoAccessView' export const TranscriptSidePanel = () => { const { data } = useConfig() - const { isLoggedIn } = useUser() - const [isLoading, setIsLoading] = useState(false) const { t } = useTranslation('rooms', { keyPrefix: 'transcript' }) @@ -153,179 +150,23 @@ export const TranscriptSidePanel = () => { if (hasFeatureWithoutAdminRights) { return ( -
- {''} - {t('notAdminOrOwner.heading')} - - {t('notAdminOrOwner.body')} -
- {data?.support?.help_article_transcript && ( - - {t('notAdminOrOwner.linkMore')} - - )} -
- {!isLoggedIn && ( -
- - {t('notAdminOrOwner.login.heading')} - - - {t('notAdminOrOwner.login.body')} - -
- -
-
- )} -
+ ) } if (!hasTranscriptAccess) { return ( -
- {''} - {t('premium.heading')} - - {t('premium.body')}{' '} - {data?.support?.help_article_transcript && ( - - {t('linkMore')} - - )} - - {!isLoggedIn && ( -
- - {t('premium.login.heading')} - - {t('premium.login.body')} -
- -
-
- )} -
+ ) } diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json index c72c1fba..2f03f06b 100644 --- a/src/frontend/src/locales/de/rooms.json +++ b/src/frontend/src/locales/de/rooms.json @@ -338,6 +338,7 @@ "premium": { "heading": "Premium-Funktion", "body": "Diese Funktion ist öffentlichen Bediensteten vorbehalten. Wenn Ihre E-Mail-Adresse nicht autorisiert ist, kontaktieren Sie bitte den Support, um Zugriff zu erhalten.", + "linkMore": "Mehr erfahren", "login": { "heading": "Anmeldung erforderlich", "body": "Nur der Ersteller des Meetings oder ein Administrator kann die Transkription starten. Melden Sie sich an, um Ihre Berechtigungen zu überprüfen." diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json index a58b7154..f7544691 100644 --- a/src/frontend/src/locales/en/rooms.json +++ b/src/frontend/src/locales/en/rooms.json @@ -338,6 +338,7 @@ "premium": { "heading": "Premium feature", "body": "This feature is reserved for public agents. If your email address is not authorized, please contact support to get access.", + "linkMore": "Learn more", "login": { "heading": "You are not logged in!", "body": "You must be logged in to use this feature. Please log in, then try again." diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json index c9066505..85b0e823 100644 --- a/src/frontend/src/locales/fr/rooms.json +++ b/src/frontend/src/locales/fr/rooms.json @@ -338,6 +338,7 @@ "premium": { "heading": "Fonctionnalité premium", "body": "Cette fonctionnalité est réservée aux agents publics. Si votre adresse email n’est pas autorisée, contactez le support pour obtenir l'accès.", + "linkMore": "En savoir plus", "login": { "heading": "Vous n'êtes pas connecté !", "body": "Vous devez être connecté pour utiliser cette fonctionnalité. Connectez-vous, puis réessayez." diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json index dadc34bb..e83aadc8 100644 --- a/src/frontend/src/locales/nl/rooms.json +++ b/src/frontend/src/locales/nl/rooms.json @@ -338,6 +338,7 @@ "premium": { "heading": "Premiumfunctie", "body": "Deze functie is voorbehouden aan openbare medewerkers. Als uw e-mailadres niet is toegestaan, neem dan contact op met de support om toegang te krijgen.", + "linkMore": "Meer informatie", "login": { "heading": "Inloggen vereist", "body": "Alleen de maker van de vergadering of een beheerder kan de transcriptie starten. Log in om uw machtigingen te controleren."