♻️(frontend) refactor recording side panels to reduce code duplication
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.
This commit is contained in:
committed by
aleb_the_flash
parent
9ebf2f277b
commit
236245740f
@@ -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 (
|
||||
<div
|
||||
className={css({
|
||||
backgroundColor: 'primary.50',
|
||||
borderRadius: '5px',
|
||||
paddingY: '1rem',
|
||||
paddingX: '1rem',
|
||||
marginTop: '1rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
})}
|
||||
>
|
||||
<H
|
||||
lvl={3}
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: '0.35rem',
|
||||
})}
|
||||
>
|
||||
{heading}
|
||||
</H>
|
||||
<Text variant="smNote" wrap="pretty">
|
||||
{body}
|
||||
</Text>
|
||||
<div
|
||||
className={css({
|
||||
marginTop: '1rem',
|
||||
})}
|
||||
>
|
||||
<LoginButton proConnectHint={false} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -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 (
|
||||
<Div
|
||||
display="flex"
|
||||
overflowY="scroll"
|
||||
padding="0 1.5rem"
|
||||
flexGrow={1}
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<img
|
||||
src={imagePath}
|
||||
alt=""
|
||||
className={css({
|
||||
minHeight: '309px',
|
||||
height: '309px',
|
||||
marginBottom: '1rem',
|
||||
'@media (max-height: 700px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '45%',
|
||||
marginBottom: '0.3rem',
|
||||
},
|
||||
'@media (max-height: 530px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '40%',
|
||||
marginBottom: '0.1rem',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Text>{t(`${i18nKey}.heading`)}</Text>
|
||||
<Text
|
||||
variant="note"
|
||||
centered
|
||||
className={css({
|
||||
textStyle: 'sm',
|
||||
marginBottom: '2.5rem',
|
||||
marginTop: '0.25rem',
|
||||
'@media (max-height: 700px)': {
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
})}
|
||||
>
|
||||
{t(`${i18nKey}.body`)}
|
||||
<br />
|
||||
{helpArticle && (
|
||||
<A href={helpArticle} target="_blank">
|
||||
{t(`${i18nKey}.linkMore`)}
|
||||
</A>
|
||||
)}
|
||||
</Text>
|
||||
{!isLoggedIn && (
|
||||
<LoginPrompt
|
||||
heading={t(`${i18nKey}.login.heading`)}
|
||||
body={t(`${i18nKey}.login.body`)}
|
||||
/>
|
||||
)}
|
||||
</Div>
|
||||
)
|
||||
}
|
||||
@@ -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 (
|
||||
<Div
|
||||
display="flex"
|
||||
overflowY="scroll"
|
||||
padding="0 1.5rem"
|
||||
flexGrow={1}
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<img
|
||||
src="/assets/intro-slider/4.png"
|
||||
alt={''}
|
||||
className={css({
|
||||
minHeight: '309px',
|
||||
height: '309px',
|
||||
marginBottom: '1rem',
|
||||
'@media (max-height: 700px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '45%',
|
||||
marginBottom: '0.3rem',
|
||||
},
|
||||
'@media (max-height: 530px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '40%',
|
||||
marginBottom: '0.1rem',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Text>{t('notAdminOrOwner.heading')}</Text>
|
||||
<Text
|
||||
variant="note"
|
||||
wrap="balance"
|
||||
centered
|
||||
className={css({
|
||||
textStyle: 'sm',
|
||||
marginBottom: '2.5rem',
|
||||
marginTop: '0.25rem',
|
||||
'@media (max-height: 700px)': {
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
})}
|
||||
>
|
||||
{t('notAdminOrOwner.body')}
|
||||
<br />
|
||||
{data?.support?.help_article_recording && (
|
||||
<A href={data.support.help_article_recording} target="_blank">
|
||||
{t('notAdminOrOwner.linkMore')}
|
||||
</A>
|
||||
)}
|
||||
</Text>
|
||||
{!isLoggedIn && (
|
||||
<div
|
||||
className={css({
|
||||
backgroundColor: 'primary.50',
|
||||
borderRadius: '5px',
|
||||
paddingY: '1rem',
|
||||
paddingX: '1rem',
|
||||
marginTop: '1rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
})}
|
||||
>
|
||||
<H
|
||||
lvl={3}
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: '0.35rem',
|
||||
})}
|
||||
>
|
||||
{t('notAdminOrOwner.login.heading')}
|
||||
</H>
|
||||
<Text variant="smNote" wrap="balance">
|
||||
{t('notAdminOrOwner.login.body')}
|
||||
</Text>
|
||||
<div
|
||||
className={css({
|
||||
marginTop: '1rem',
|
||||
})}
|
||||
>
|
||||
<LoginButton proConnectHint={false} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Div>
|
||||
<NoAccessView
|
||||
i18nKeyPrefix="screenRecording"
|
||||
i18nKey="notAdminOrOwner"
|
||||
helpArticle={data?.support?.help_article_recording}
|
||||
imagePath="/assets/intro-slider/4.png"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<Div
|
||||
display="flex"
|
||||
overflowY="scroll"
|
||||
padding="0 1.5rem"
|
||||
flexGrow={1}
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<img
|
||||
src="/assets/intro-slider/3.png"
|
||||
alt={''}
|
||||
className={css({
|
||||
minHeight: '309px',
|
||||
height: '309px',
|
||||
marginBottom: '1rem',
|
||||
'@media (max-height: 700px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '45%',
|
||||
marginBottom: '0.3rem',
|
||||
},
|
||||
'@media (max-height: 530px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '40%',
|
||||
marginBottom: '0.1rem',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Text>{t('notAdminOrOwner.heading')}</Text>
|
||||
<Text
|
||||
variant="note"
|
||||
wrap="balance"
|
||||
centered
|
||||
className={css({
|
||||
textStyle: 'sm',
|
||||
marginBottom: '2.5rem',
|
||||
marginTop: '0.25rem',
|
||||
'@media (max-height: 700px)': {
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
})}
|
||||
>
|
||||
{t('notAdminOrOwner.body')}
|
||||
<br />
|
||||
{data?.support?.help_article_transcript && (
|
||||
<A href={data.support.help_article_transcript} target="_blank">
|
||||
{t('notAdminOrOwner.linkMore')}
|
||||
</A>
|
||||
)}
|
||||
</Text>
|
||||
{!isLoggedIn && (
|
||||
<div
|
||||
className={css({
|
||||
backgroundColor: 'primary.50',
|
||||
borderRadius: '5px',
|
||||
paddingY: '1rem',
|
||||
paddingX: '1rem',
|
||||
marginTop: '1rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
})}
|
||||
>
|
||||
<H
|
||||
lvl={3}
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: '0.35rem',
|
||||
})}
|
||||
>
|
||||
{t('notAdminOrOwner.login.heading')}
|
||||
</H>
|
||||
<Text variant="smNote" wrap="balance">
|
||||
{t('notAdminOrOwner.login.body')}
|
||||
</Text>
|
||||
<div
|
||||
className={css({
|
||||
marginTop: '1rem',
|
||||
})}
|
||||
>
|
||||
<LoginButton proConnectHint={false} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Div>
|
||||
<NoAccessView
|
||||
i18nKeyPrefix="transcript"
|
||||
i18nKey="notAdminOrOwner"
|
||||
helpArticle={data?.support?.help_article_transcript}
|
||||
imagePath="/assets/intro-slider/3.png"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (!hasTranscriptAccess) {
|
||||
return (
|
||||
<Div
|
||||
display="flex"
|
||||
overflowY="scroll"
|
||||
padding="0 1.5rem"
|
||||
flexGrow={1}
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<img
|
||||
src="/assets/intro-slider/3.png"
|
||||
alt={''}
|
||||
className={css({
|
||||
minHeight: '309px',
|
||||
height: '309px',
|
||||
marginBottom: '1rem',
|
||||
'@media (max-height: 700px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '45%',
|
||||
marginBottom: '0.3rem',
|
||||
},
|
||||
'@media (max-height: 530px)': {
|
||||
height: 'auto',
|
||||
minHeight: 'auto',
|
||||
maxHeight: '40%',
|
||||
marginBottom: '0.1rem',
|
||||
},
|
||||
})}
|
||||
/>
|
||||
<Text>{t('premium.heading')}</Text>
|
||||
<Text
|
||||
variant="note"
|
||||
centered
|
||||
className={css({
|
||||
textStyle: 'sm',
|
||||
marginBottom: '2.5rem',
|
||||
marginTop: '0.25rem',
|
||||
'@media (max-height: 700px)': {
|
||||
marginBottom: '1rem',
|
||||
},
|
||||
})}
|
||||
>
|
||||
{t('premium.body')}{' '}
|
||||
{data?.support?.help_article_transcript && (
|
||||
<A href={data.support.help_article_transcript} target="_blank">
|
||||
{t('linkMore')}
|
||||
</A>
|
||||
)}
|
||||
</Text>
|
||||
{!isLoggedIn && (
|
||||
<div
|
||||
className={css({
|
||||
backgroundColor: 'primary.50',
|
||||
borderRadius: '5px',
|
||||
paddingY: '1rem',
|
||||
paddingX: '1rem',
|
||||
marginTop: '1rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
})}
|
||||
>
|
||||
<H
|
||||
lvl={3}
|
||||
className={css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: '0.35rem',
|
||||
})}
|
||||
>
|
||||
{t('premium.login.heading')}
|
||||
</H>
|
||||
<Text variant="smNote">{t('premium.login.body')}</Text>
|
||||
<div
|
||||
className={css({
|
||||
marginTop: '1rem',
|
||||
})}
|
||||
>
|
||||
<LoginButton proConnectHint={false} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Div>
|
||||
<NoAccessView
|
||||
i18nKeyPrefix="transcript"
|
||||
i18nKey="premium"
|
||||
helpArticle={data?.support?.help_article_transcript}
|
||||
imagePath="/assets/intro-slider/3.png"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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."
|
||||
|
||||
Reference in New Issue
Block a user